From: Jakub Jelinek Date: Mon, 5 Jan 2015 21:47:51 +0000 (+0100) Subject: re PR sanitizer/64265 (r217669 broke tsan) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fca4adf2095dfcd453ab32250984d85ff66bbd32;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f62aed21f04..286ec01a4e3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2015-01-05 Jakub Jelinek + 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 diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d35734f8bb4..b237cbf866a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -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; diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 50f569455a3..50e3c5114de 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -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 diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 06d42648ccb..f7ebce34225 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -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) diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 902eb955d39..5518d404ff9 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -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 diff --git a/gcc/tsan.c b/gcc/tsan.c index 1bc146f198d..567a4218bcd 100644 --- a/gcc/tsan.c +++ b/gcc/tsan.c @@ -704,6 +704,47 @@ instrument_gimple (gimple_stmt_iterator *gsi) return instrumented; } +/* Replace TSAN_FUNC_EXIT internal call with function exit tsan builtin. */ + +static void +replace_func_exit (gimple stmt) +{ + 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); +} + +/* Instrument function exit. Used when TSAN_FUNC_EXIT does not exist. */ + +static void +instrument_func_exit (void) +{ + location_t loc; + basic_block exit_bb; + gimple_stmt_iterator gsi; + gimple stmt, g; + tree builtin_decl; + edge e; + edge_iterator ei; + + /* Find all function exits. */ + exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun); + 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 + || gimple_call_builtin_p (stmt, BUILT_IN_RETURN)); + loc = gimple_location (stmt); + builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT); + g = gimple_build_call (builtin_decl, 0); + gimple_set_location (g, loc); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + } +} + /* Instruments all interesting memory accesses in the current function. Return true if func entry/exit should be instrumented. */ @@ -713,10 +754,38 @@ instrument_memory_accesses (void) basic_block bb; gimple_stmt_iterator gsi; bool fentry_exit_instrument = false; + bool func_exit_seen = false; + auto_vec tsan_func_exits; 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); + { + 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; } @@ -745,35 +814,6 @@ instrument_func_entry (void) gsi_insert_seq_on_edge_immediate (e, seq); } -/* Instruments function exits. */ - -static void -instrument_func_exit (void) -{ - location_t loc; - basic_block exit_bb; - gimple_stmt_iterator gsi; - gimple stmt, g; - tree builtin_decl; - edge e; - edge_iterator ei; - - /* Find all function exits. */ - exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun); - 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 - || gimple_call_builtin_p (stmt, BUILT_IN_RETURN)); - loc = gimple_location (stmt); - builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_FUNC_EXIT); - g = gimple_build_call (builtin_decl, 0); - gimple_set_location (g, loc); - gsi_insert_before (&gsi, g, GSI_SAME_STMT); - } -} - /* 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; }