summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>2017-07-03 11:48:47 +0000
committermarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>2017-07-03 11:48:47 +0000
commitf91fab922e3d6ef6c7226548ab2346fc389f98d8 (patch)
tree87b35ad9ae9f27b7dc9ca3acafa2088e9bff3d82
parentabf900f6121f835fe39689057d7de40b9bc04ad7 (diff)
downloadgcc-f91fab922e3d6ef6c7226548ab2346fc389f98d8.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@249903 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/doc/extend.texi10
-rw-r--r--gcc/sanopt.c138
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/asan/function-argument-1.C30
-rw-r--r--gcc/testsuite/g++.dg/asan/function-argument-2.C24
-rw-r--r--gcc/testsuite/g++.dg/asan/function-argument-3.C27
7 files changed, 244 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 721901cea1c..905c6916262 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+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.
+
2017-07-03 Richard Biener <rguenther@suse.de>
* tree-vect-loop.c (vect_create_epilog_for_reduction): Revert
@@ -5,6 +12,12 @@
2017-07-03 Martin Liska <mliska@suse.cz>
+ PR other/78366
+ * doc/extend.texi: Document when a resolver function is
+ generated for target_clones.
+
+2017-07-03 Martin Liska <mliska@suse.cz>
+
* asan.c (asan_emit_stack_protection): Unpoison just red zones
and shadow memory of auto variables which are subject of
use-after-scope sanitization.
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<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;
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 <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 Richard Sandiford <richard.sandiford@linaro.org>
* 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.*" }