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


Sorry, I attached an incorrect patch.txt yesterday. This is the correct one.

Thanks,
Wei.

On Fri, Nov 2, 2012 at 6:31 PM, Wei Mi <wmi@google.com> wrote:
> 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]