re PR sanitizer/64265 (r217669 broke tsan)
PR sanitizer/64265 * gimplify.c (gimplify_function_tree): Add TSAN_FUNC_EXIT internal call as cleanup of the whole body. * internal-fn.def (TSAN_FUNC_EXIT): New internal call. * tsan.c (replace_func_exit): New function. (instrument_func_exit): Moved earlier. (instrument_memory_accesses): Adjust TSAN_FUNC_EXIT internal calls. Call instrument_func_exit if no TSAN_FUNC_EXIT internal calls have been found. (tsan_pass): Don't call instrument_func_exit. * internal-fn.c (expand_TSAN_FUNC_EXIT): New function. * tree-inline.c (copy_bb): Drop TSAN_FUNC_EXIT internal calls during inlining. From-SVN: r219202
This commit is contained in:
parent
e534110031
commit
fca4adf209
@ -1,5 +1,19 @@
|
||||
2015-01-05 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR sanitizer/64265
|
||||
* gimplify.c (gimplify_function_tree): Add TSAN_FUNC_EXIT internal
|
||||
call as cleanup of the whole body.
|
||||
* internal-fn.def (TSAN_FUNC_EXIT): New internal call.
|
||||
* tsan.c (replace_func_exit): New function.
|
||||
(instrument_func_exit): Moved earlier.
|
||||
(instrument_memory_accesses): Adjust TSAN_FUNC_EXIT internal calls.
|
||||
Call instrument_func_exit if no TSAN_FUNC_EXIT internal calls have
|
||||
been found.
|
||||
(tsan_pass): Don't call instrument_func_exit.
|
||||
* internal-fn.c (expand_TSAN_FUNC_EXIT): New function.
|
||||
* tree-inline.c (copy_bb): Drop TSAN_FUNC_EXIT internal calls during
|
||||
inlining.
|
||||
|
||||
PR sanitizer/64344
|
||||
* ubsan.h (ubsan_instrument_float_cast): Add ARG argument.
|
||||
* ubsan.c (ubsan_instrument_float_cast): Add ARG argument, pass
|
||||
|
@ -9049,6 +9049,22 @@ gimplify_function_tree (tree fndecl)
|
||||
seq = NULL;
|
||||
gimple_seq_add_stmt (&seq, new_bind);
|
||||
gimple_set_body (fndecl, seq);
|
||||
bind = new_bind;
|
||||
}
|
||||
|
||||
if (flag_sanitize & SANITIZE_THREAD)
|
||||
{
|
||||
gcall *call = gimple_build_call_internal (IFN_TSAN_FUNC_EXIT, 0);
|
||||
gimple tf = gimple_build_try (seq, call, GIMPLE_TRY_FINALLY);
|
||||
gbind *new_bind = gimple_build_bind (NULL, tf, gimple_bind_block (bind));
|
||||
/* Clear the block for BIND, since it is no longer directly inside
|
||||
the function, but within a try block. */
|
||||
gimple_bind_set_block (bind, NULL);
|
||||
/* Replace the current function body with the body
|
||||
wrapped in the try/finally TF. */
|
||||
seq = NULL;
|
||||
gimple_seq_add_stmt (&seq, new_bind);
|
||||
gimple_set_body (fndecl, seq);
|
||||
}
|
||||
|
||||
DECL_SAVED_TREE (fndecl) = NULL_TREE;
|
||||
|
@ -208,6 +208,14 @@ expand_ASAN_CHECK (gcall *stmt ATTRIBUTE_UNUSED)
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* This should get expanded in the tsan pass. */
|
||||
|
||||
static void
|
||||
expand_TSAN_FUNC_EXIT (gcall *)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Helper function for expand_addsub_overflow. Return 1
|
||||
if ARG interpreted as signed in its precision is known to be always
|
||||
positive or 2 if ARG is known to be always negative, or 3 if ARG may
|
||||
|
@ -60,3 +60,4 @@ DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".W...")
|
||||
DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
DEF_INTERNAL_FN (TSAN_FUNC_EXIT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
|
||||
|
@ -1907,7 +1907,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|
||||
gsi_replace (©_gsi, new_call, false);
|
||||
stmt = new_call;
|
||||
}
|
||||
else if (is_gimple_call (stmt)
|
||||
else if (call_stmt
|
||||
&& id->call_stmt
|
||||
&& (decl = gimple_call_fndecl (stmt))
|
||||
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
|
||||
@ -1934,6 +1934,15 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
|
||||
gsi_replace (©_gsi, new_stmt, false);
|
||||
stmt = new_stmt;
|
||||
}
|
||||
else if (call_stmt
|
||||
&& id->call_stmt
|
||||
&& gimple_call_internal_p (stmt)
|
||||
&& gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
|
||||
{
|
||||
/* Drop TSAN_FUNC_EXIT () internal calls during inlining. */
|
||||
gsi_remove (©_gsi, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Statements produced by inlining can be unfolded, especially
|
||||
when we constant propagated some operands. We can't fold
|
||||
|
119
gcc/tsan.c
119
gcc/tsan.c
@ -704,48 +704,19 @@ instrument_gimple (gimple_stmt_iterator *gsi)
|
||||
return instrumented;
|
||||
}
|
||||
|
||||
/* Instruments all interesting memory accesses in the current function.
|
||||
Return true if func entry/exit should be instrumented. */
|
||||
|
||||
static bool
|
||||
instrument_memory_accesses (void)
|
||||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator gsi;
|
||||
bool fentry_exit_instrument = false;
|
||||
|
||||
FOR_EACH_BB_FN (bb, cfun)
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
fentry_exit_instrument |= instrument_gimple (&gsi);
|
||||
return fentry_exit_instrument;
|
||||
}
|
||||
|
||||
/* Instruments function entry. */
|
||||
/* Replace TSAN_FUNC_EXIT internal call with function exit tsan builtin. */
|
||||
|
||||
static void
|
||||
instrument_func_entry (void)
|
||||
replace_func_exit (gimple stmt)
|
||||
{
|
||||
tree ret_addr, builtin_decl;
|
||||
gimple g;
|
||||
gimple_seq seq = NULL;
|
||||
|
||||
builtin_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
|
||||
g = gimple_build_call (builtin_decl, 1, integer_zero_node);
|
||||
ret_addr = make_ssa_name (ptr_type_node);
|
||||
gimple_call_set_lhs (g, ret_addr);
|
||||
gimple_set_location (g, cfun->function_start_locus);
|
||||
gimple_seq_add_stmt_without_update (&seq, g);
|
||||
|
||||
builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY);
|
||||
g = gimple_build_call (builtin_decl, 1, ret_addr);
|
||||
gimple_set_location (g, cfun->function_start_locus);
|
||||
gimple_seq_add_stmt_without_update (&seq, g);
|
||||
|
||||
edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
gsi_insert_seq_on_edge_immediate (e, seq);
|
||||
tree builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT);
|
||||
gimple g = gimple_build_call (builtin_decl, 0);
|
||||
gimple_set_location (g, cfun->function_end_locus);
|
||||
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
|
||||
gsi_replace (&gsi, g, true);
|
||||
}
|
||||
|
||||
/* Instruments function exits. */
|
||||
/* Instrument function exit. Used when TSAN_FUNC_EXIT does not exist. */
|
||||
|
||||
static void
|
||||
instrument_func_exit (void)
|
||||
@ -774,6 +745,75 @@ instrument_func_exit (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Instruments all interesting memory accesses in the current function.
|
||||
Return true if func entry/exit should be instrumented. */
|
||||
|
||||
static bool
|
||||
instrument_memory_accesses (void)
|
||||
{
|
||||
basic_block bb;
|
||||
gimple_stmt_iterator gsi;
|
||||
bool fentry_exit_instrument = false;
|
||||
bool func_exit_seen = false;
|
||||
auto_vec<gimple> tsan_func_exits;
|
||||
|
||||
FOR_EACH_BB_FN (bb, cfun)
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
gimple stmt = gsi_stmt (gsi);
|
||||
if (is_gimple_call (stmt)
|
||||
&& gimple_call_internal_p (stmt)
|
||||
&& gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT)
|
||||
{
|
||||
if (fentry_exit_instrument)
|
||||
replace_func_exit (stmt);
|
||||
else
|
||||
tsan_func_exits.safe_push (stmt);
|
||||
func_exit_seen = true;
|
||||
}
|
||||
else
|
||||
fentry_exit_instrument |= instrument_gimple (&gsi);
|
||||
}
|
||||
unsigned int i;
|
||||
gimple stmt;
|
||||
FOR_EACH_VEC_ELT (tsan_func_exits, i, stmt)
|
||||
if (fentry_exit_instrument)
|
||||
replace_func_exit (stmt);
|
||||
else
|
||||
{
|
||||
gsi = gsi_for_stmt (stmt);
|
||||
gsi_remove (&gsi, true);
|
||||
}
|
||||
if (fentry_exit_instrument && !func_exit_seen)
|
||||
instrument_func_exit ();
|
||||
return fentry_exit_instrument;
|
||||
}
|
||||
|
||||
/* Instruments function entry. */
|
||||
|
||||
static void
|
||||
instrument_func_entry (void)
|
||||
{
|
||||
tree ret_addr, builtin_decl;
|
||||
gimple g;
|
||||
gimple_seq seq = NULL;
|
||||
|
||||
builtin_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
|
||||
g = gimple_build_call (builtin_decl, 1, integer_zero_node);
|
||||
ret_addr = make_ssa_name (ptr_type_node);
|
||||
gimple_call_set_lhs (g, ret_addr);
|
||||
gimple_set_location (g, cfun->function_start_locus);
|
||||
gimple_seq_add_stmt_without_update (&seq, g);
|
||||
|
||||
builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_ENTRY);
|
||||
g = gimple_build_call (builtin_decl, 1, ret_addr);
|
||||
gimple_set_location (g, cfun->function_start_locus);
|
||||
gimple_seq_add_stmt_without_update (&seq, g);
|
||||
|
||||
edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
gsi_insert_seq_on_edge_immediate (e, seq);
|
||||
}
|
||||
|
||||
/* ThreadSanitizer instrumentation pass. */
|
||||
|
||||
static unsigned
|
||||
@ -781,10 +821,7 @@ tsan_pass (void)
|
||||
{
|
||||
initialize_sanitizer_builtins ();
|
||||
if (instrument_memory_accesses ())
|
||||
{
|
||||
instrument_func_entry ();
|
||||
instrument_func_exit ();
|
||||
}
|
||||
instrument_func_entry ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user