diff options
author | Martin Liska <mliska@suse.cz> | 2017-07-03 13:48:47 +0200 |
---|---|---|
committer | Martin Liska <marxin@gcc.gnu.org> | 2017-07-03 11:48:47 +0000 |
commit | da4029679e2be30dc78f3f3a016226f6e2299abb (patch) | |
tree | 87b35ad9ae9f27b7dc9ca3acafa2088e9bff3d82 /gcc/sanopt.c | |
parent | b6d447f20948b35804fd780f8f1a237c9d36826f (diff) | |
download | gcc-da4029679e2be30dc78f3f3a016226f6e2299abb.zip gcc-da4029679e2be30dc78f3f3a016226f6e2299abb.tar.gz gcc-da4029679e2be30dc78f3f3a016226f6e2299abb.tar.bz2 |
ASAN: handle addressable params (PR sanitize/81040).
2017-07-03 Martin Liska <mliska@suse.cz>
PR sanitize/81040
* g++.dg/asan/function-argument-1.C: New test.
* g++.dg/asan/function-argument-2.C: New test.
* g++.dg/asan/function-argument-3.C: New test.
2017-07-03 Martin Liska <mliska@suse.cz>
PR sanitize/81040
* sanopt.c (rewrite_usage_of_param): New function.
(sanitize_rewrite_addressable_params): Likewise.
(pass_sanopt::execute): Call rewrite_usage_of_param.
From-SVN: r249903
Diffstat (limited to 'gcc/sanopt.c')
-rw-r--r-- | gcc/sanopt.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/gcc/sanopt.c b/gcc/sanopt.c index 16bdba7..7692f6a 100644 --- a/gcc/sanopt.c +++ b/gcc/sanopt.c @@ -37,6 +37,12 @@ along with GCC; see the file COPYING3. If not see #include "gimple-ssa.h" #include "tree-phinodes.h" #include "ssa-iterators.h" +#include "gimplify.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "cfghooks.h" +#include "tree-dfa.h" +#include "tree-ssa.h" /* This is used to carry information about basic blocks. It is attached to the AUX field of the standard CFG block. */ @@ -858,6 +864,135 @@ sanitize_asan_mark_poison (void) } } +/* Rewrite all usages of tree OP which is a PARM_DECL with a VAR_DECL + that is it's DECL_VALUE_EXPR. */ + +static tree +rewrite_usage_of_param (tree *op, int *walk_subtrees, void *) +{ + if (TREE_CODE (*op) == PARM_DECL && DECL_HAS_VALUE_EXPR_P (*op)) + { + *op = DECL_VALUE_EXPR (*op); + *walk_subtrees = 0; + } + + return NULL; +} + +/* For a given function FUN, rewrite all addressable parameters so that + a new automatic variable is introduced. Right after function entry + a parameter is assigned to the variable. */ + +static void +sanitize_rewrite_addressable_params (function *fun) +{ + gimple *g; + gimple_seq stmts = NULL; + bool has_any_addressable_param = false; + auto_vec<tree> clear_value_expr_list; + + for (tree arg = DECL_ARGUMENTS (current_function_decl); + arg; arg = DECL_CHAIN (arg)) + { + if (TREE_ADDRESSABLE (arg) && !TREE_ADDRESSABLE (TREE_TYPE (arg))) + { + TREE_ADDRESSABLE (arg) = 0; + /* The parameter is no longer addressable. */ + tree type = TREE_TYPE (arg); + has_any_addressable_param = true; + + /* Create a new automatic variable. */ + tree var = build_decl (DECL_SOURCE_LOCATION (arg), + VAR_DECL, DECL_NAME (arg), type); + TREE_ADDRESSABLE (var) = 1; + DECL_ARTIFICIAL (var) = 1; + + gimple_add_tmp_var (var); + + if (dump_file) + fprintf (dump_file, + "Rewriting parameter whose address is taken: %s\n", + IDENTIFIER_POINTER (DECL_NAME (arg))); + + gcc_assert (!DECL_HAS_VALUE_EXPR_P (arg)); + DECL_HAS_VALUE_EXPR_P (arg) = 1; + SET_DECL_VALUE_EXPR (arg, var); + + SET_DECL_PT_UID (var, DECL_PT_UID (arg)); + + /* Assign value of parameter to newly created variable. */ + if ((TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE)) + { + /* We need to create a SSA name that will be used for the + assignment. */ + DECL_GIMPLE_REG_P (arg) = 1; + tree tmp = get_or_create_ssa_default_def (cfun, arg); + g = gimple_build_assign (var, tmp); + gimple_set_location (g, DECL_SOURCE_LOCATION (arg)); + gimple_seq_add_stmt (&stmts, g); + } + else + { + g = gimple_build_assign (var, arg); + gimple_set_location (g, DECL_SOURCE_LOCATION (arg)); + gimple_seq_add_stmt (&stmts, g); + } + + if (target_for_debug_bind (arg)) + { + g = gimple_build_debug_bind (arg, var, NULL); + gimple_seq_add_stmt (&stmts, g); + clear_value_expr_list.safe_push (arg); + } + } + } + + if (!has_any_addressable_param) + return; + + /* Replace all usages of PARM_DECLs with the newly + created variable VAR. */ + basic_block bb; + FOR_EACH_BB_FN (bb, fun) + { + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + gimple_stmt_iterator it = gsi_for_stmt (stmt); + walk_gimple_stmt (&it, NULL, rewrite_usage_of_param, NULL); + } + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gphi *phi = dyn_cast<gphi *> (gsi_stmt (gsi)); + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) + { + hash_set<tree> visited_nodes; + walk_tree (gimple_phi_arg_def_ptr (phi, i), + rewrite_usage_of_param, NULL, &visited_nodes); + } + } + } + + /* Unset value expr for parameters for which we created debug bind + expressions. */ + unsigned i; + tree arg; + FOR_EACH_VEC_ELT (clear_value_expr_list, i, arg) + { + DECL_HAS_VALUE_EXPR_P (arg) = 0; + SET_DECL_VALUE_EXPR (arg, NULL_TREE); + } + + /* Insert default assignments at the beginning of a function. */ + basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (fun); + entry_bb = split_edge (single_succ_edge (entry_bb)); + + gimple_stmt_iterator gsi = gsi_start_bb (entry_bb); + gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); +} + unsigned int pass_sanopt::execute (function *fun) { @@ -891,6 +1026,9 @@ pass_sanopt::execute (function *fun) sanitize_asan_mark_poison (); } + if (asan_sanitize_stack_p ()) + sanitize_rewrite_addressable_params (fun); + bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD; |