From da4029679e2be30dc78f3f3a016226f6e2299abb Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 3 Jul 2017 13:48:47 +0200 Subject: [PATCH] ASAN: handle addressable params (PR sanitize/81040). 2017-07-03 Martin Liska 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 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 --- gcc/ChangeLog | 13 ++ gcc/doc/extend.texi | 10 +- gcc/sanopt.c | 138 ++++++++++++++++++ gcc/testsuite/ChangeLog | 7 + .../g++.dg/asan/function-argument-1.C | 30 ++++ .../g++.dg/asan/function-argument-2.C | 24 +++ .../g++.dg/asan/function-argument-3.C | 27 ++++ 7 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/asan/function-argument-1.C create mode 100644 gcc/testsuite/g++.dg/asan/function-argument-2.C create mode 100644 gcc/testsuite/g++.dg/asan/function-argument-3.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 721901cea1c..905c6916262 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,8 +1,21 @@ +2017-07-03 Martin Liska + + PR sanitize/81040 + * sanopt.c (rewrite_usage_of_param): New function. + (sanitize_rewrite_addressable_params): Likewise. + (pass_sanopt::execute): Call rewrite_usage_of_param. + 2017-07-03 Richard Biener * tree-vect-loop.c (vect_create_epilog_for_reduction): Revert back to using VIEW_CONVERT_EXPR. +2017-07-03 Martin Liska + + PR other/78366 + * doc/extend.texi: Document when a resolver function is + generated for target_clones. + 2017-07-03 Martin Liska * asan.c (asan_emit_stack_protection): Unpoison just red zones diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 84150ccf144..03ba8fc436c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3278,16 +3278,16 @@ are the same as for @code{target} attribute. For instance, on an x86, you could compile a function with @code{target_clones("sse4.1,avx")}. GCC creates two function clones, one compiled with @option{-msse4.1} and another with @option{-mavx}. -It also creates a resolver function (see the @code{ifunc} attribute -above) that dynamically selects a clone suitable for current -architecture. On a PowerPC, you can compile a function with @code{target_clones("cpu=power9,default")}. GCC will create two function clones, one compiled with @option{-mcpu=power9} and another -with the default options. It also creates a resolver function (see +with the default options. + +It also creates a resolver function (see the @code{ifunc} attribute above) that dynamically selects a clone -suitable for current architecture. +suitable for current architecture. The resolver is created only if there +is a usage of a function with @code{target_clones} attribute. @item unused @cindex @code{unused} function attribute diff --git a/gcc/sanopt.c b/gcc/sanopt.c index 16bdba76042..7692f6a9db7 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 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 (gsi_stmt (gsi)); + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) + { + hash_set 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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f5d2f8be789..09d9d7b3397 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-07-03 Martin Liska + + 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 Richard Sandiford * gcc.dg/vect/bb-slp-pr65935.c: Expect SLP to be used in main diff --git a/gcc/testsuite/g++.dg/asan/function-argument-1.C b/gcc/testsuite/g++.dg/asan/function-argument-1.C new file mode 100644 index 00000000000..148c4628316 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/function-argument-1.C @@ -0,0 +1,30 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +struct A +{ + int a[5]; +}; + +static __attribute__ ((noinline)) int +goo (A *a) +{ + int *ptr = &a->a[0]; + return *(volatile int *) (ptr - 1); +} + +__attribute__ ((noinline)) int +foo (A arg) +{ + return goo (&arg); +} + +int +main () +{ + return foo (A ()); +} + +// { dg-output "ERROR: AddressSanitizer: stack-buffer-underflow on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size . at.*" } +// { dg-output ".*'arg' <== Memory access at offset \[0-9\]* underflows this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/function-argument-2.C b/gcc/testsuite/g++.dg/asan/function-argument-2.C new file mode 100644 index 00000000000..3a7c33bdaaa --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/function-argument-2.C @@ -0,0 +1,24 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +static __attribute__ ((noinline)) int +goo (int *a) +{ + return *(volatile int *)a; +} + +__attribute__ ((noinline)) int +foo (char arg) +{ + return goo ((int *)&arg); +} + +int +main () +{ + return foo (12); +} + +// { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size . at.*" } +// { dg-output ".*'arg' <== Memory access at offset \[0-9\]* partially overflows this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/function-argument-3.C b/gcc/testsuite/g++.dg/asan/function-argument-3.C new file mode 100644 index 00000000000..14617ba8425 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/function-argument-3.C @@ -0,0 +1,27 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +typedef int v4si __attribute__ ((vector_size (16))); + +static __attribute__ ((noinline)) int +goo (v4si *a) +{ + return (*(volatile v4si *) (a + 1))[2]; +} + +__attribute__ ((noinline)) int +foo (v4si arg) +{ + return goo (&arg); +} + +int +main () +{ + v4si v = {1,2,3,4}; + return foo (v); +} + +// { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size . at.*" } +// { dg-output ".*'arg' <== Memory access at offset \[0-9\]* overflows this variable.*" } -- 2.30.2