This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [tsan] ThreadSanitizer instrumentation part


Hi,

Thanks for so many useful comments! I update the file according to the
comments. The major changes include adding sanitizer.def and
generating gimple directly. New patch file is attached.

> On Wed, Oct 31, 2012 at 11:34:10AM -0700, Wei Mi wrote:
>> gcc/ChangeLog:
>> 2012-10-31  Wei Mi  <wmi@gmail.com>
>
> If Dmitry wrote parts of the patch, it would be nice to mention
> him in the ChangeLog too.

> All ChangeLog entries should end with a dot.

Changed.

2012-10-31  Dmitry Vyukov  <dvyukov@google.com>
                     Wei Mi  <wmi@google.com>

        * Makefile.in (tsan.o): New.
        (BUILTINS_DEF): Add sanitizer.def.
        * sanitizer.def: 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
        -fthread_sanitizer is on.
        * tsan.c: New file about tsan.
        * tsan.h: Ditto.


>>  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 */
>
> Why this?  Simply don't include that header in tsan.c, it is already
> included by basic-block.h.

Remove cfghooks.h from tsan.c. Remove the #ifdef GCC_CFGHOOKS_H from cfghooks.h

> Can't google just assign the code to FSF, and use a standard boilerplate
> as everything else in gcc/ ?

Copy from asan header and make some change.

>> +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;
>> +}
> ...
>
> Instead of this (but same applies to asan), I think we should just consider
> putting it into builtins.def (or have sanitizer.def like there is sync.def
> or omp-builtins.def).  The problem might be non-C/C++ family frontends
> though.

Create sanitizer.def and use builtin_decl_implicit to create builtin decls.

>> +  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;
>
> int_size_in_bytes.

Changed.

> preferrably without building everything as trees, then gimplifying it.

Generate gimple directly. Remove funcs: instr_memory_access,
instr_vptr_update, instr_func_entry, instr_func_exit

> For func_calls and func_mops, I believe why you need two variables instead
> of just one, and why the function can't just return a bool whether
> entry/exit needs to be instrumented or not.

instrument_memory_accesses return a bool indicating whether or not
entry/exit needs to be instrumented. func_calls and func_mops removed.

>> +set_location (gimple_seq seq, location_t loc)
>> +{
>> +  gimple_seq_node n;
>> +
>> +  for (n = gimple_seq_first (seq); n != NULL; n = n->gsbase.next)
>
> This really should use a stmt iterator.

set_location removed. set gimple location using gimple_set_location
everytime a new gimple statement is inserted.

>> +  FOR_EACH_BB (bb)
>> +    {
>> +      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> +        {
>> +          instrument_gimple (gsi);
>> +        }
>> +    }
>
> Extraneous two pairs of {}s.

Fixed.

>> +struct gimple_opt_pass pass_tsan = {{
>
> Please watch formatting of other gimple_opt_pass structures.
> {{ isn't used anywhere.

Fixed.

> Is that the option that LLVM uses (I'm talking about -faddress-sanitizer
> in LLVM vs. -fasan right now in GCC, isn't that similar?).

Fixed.

> +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;
> +}
>
> The above can crash the compiler btw, as that static tree decl
> (in many other functions) is not GTY(()) marked (must be file scope for
> that), thus ggc_collect might free it.  Also, please use type
> instead of typ for variable names.

Func get_init_decl removed after generating gimple directly.

>> +  /* 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);
>
> Inserting stmts after a call may or may not work.  E.g. if the call
> can throw, it must be the last stmt in a basic block, so then the
> stmts need to be inserted on a successor edge.  Similarly noreturn
> call must be last (but in that case it shouldn't have lhs).

Add processing for call which can throw.
  if (is_gimple_call (stmt) && is_write)
    {
      int flags = gimple_call_flags (stmt);
      /* If the call can throw, it must be the last stmt in
       * a basicblock, so the instrumented stmts need to be
       * inserted on a successor edge. */
      if (!(flags & ECF_NOTHROW))
        {
          bb = gsi_bb(gsi);
          succ_edge = single_succ_edge (bb);
          succ_bb = split_edge (succ_edge);
          gsi = gsi_start_bb (succ_bb);
        }
      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
    }
  else
    gsi_insert_before (&gsi, g, GSI_SAME_STMT);

>> +  gcode = gimple_code (stmt);
>> +  if (gcode == GIMPLE_CALL)
>
> is_gimple_call (stmt)

Fixed.

>> +  else if (gcode == GIMPLE_ASSIGN)
>
> is_gimple_assign (stmt)

Fixed.

>> +    {
>> +      /* Handle assignment lhs as store.  */
>> +      lhs = gimple_assign_lhs (stmt);
>> +      instrument_expr (gsi, lhs, 1);
>
> To find what a store or load is, you can just use the new
> gimple_store_p (stmt) and gimple_assign_load_p (stmt)
> predicates, or at least just do gimple_assign_single_p (stmt)
> to guard instrument_expr calls on both lhs and rhs1.
> No need to scan all operands, only single rhs assignments
> can be loads.

Fixed:
  else if (is_gimple_assign (stmt))
    {
      if (gimple_store_p (stmt))
        {
          lhs = gimple_assign_lhs (stmt);
          instrumented = instrument_expr (gsi, lhs, true);
        }
      if (gimple_assign_single_p (stmt))
        {
          rhs = gimple_assign_rhs1 (stmt);
          instrumented = instrument_expr (gsi, rhs, false);
        }
    }

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

Fixed.

>> +static tree
>> +get_memory_access_decl (int is_write, unsigned size)
>
> Change is_write to type bool.

Fixed.

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

The cache is removed after we use builtin_decl_implicit to create builtin decls.

>> +  is_write = !!is_write;
>
>
> No need for this after making is_write bool.

Fixed.

> Missing function comment:
>
> /* This function returns the function decl for __tsan_init.  */
>
>> +static tree
>> +get_init_decl (void)
>> +{
>> +  tree typ;
>> +  return decl;
>> +}
>> +

The func is removed.

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

Fixed.

>> +        return 1;
>
> returns true;
>
>> +    }
>> +  return 0;
>
> returns false;

Fixed.

>> +is_load_of_const (tree expr, int is_write)
>
> Better name: is_load_of_const_p (...)

Fixed.

>> +void tsan_finish_file (void)
>
> function name starts a new line.

Fixed.

Thanks,
Wei.

Attachment: patch.txt
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]