Commit da402967 by Martin Liska Committed by Martin Liska

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
parent b6d447f2
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> 2017-07-03 Richard Biener <rguenther@suse.de>
* tree-vect-loop.c (vect_create_epilog_for_reduction): Revert * tree-vect-loop.c (vect_create_epilog_for_reduction): Revert
...@@ -5,6 +12,12 @@ ...@@ -5,6 +12,12 @@
2017-07-03 Martin Liska <mliska@suse.cz> 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 * asan.c (asan_emit_stack_protection): Unpoison just red zones
and shadow memory of auto variables which are subject of and shadow memory of auto variables which are subject of
use-after-scope sanitization. use-after-scope sanitization.
......
...@@ -3278,16 +3278,16 @@ are the same as for @code{target} attribute. ...@@ -3278,16 +3278,16 @@ are the same as for @code{target} attribute.
For instance, on an x86, you could compile a function with For instance, on an x86, you could compile a function with
@code{target_clones("sse4.1,avx")}. GCC creates two function clones, @code{target_clones("sse4.1,avx")}. GCC creates two function clones,
one compiled with @option{-msse4.1} and another with @option{-mavx}. 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 On a PowerPC, you can compile a function with
@code{target_clones("cpu=power9,default")}. GCC will create two @code{target_clones("cpu=power9,default")}. GCC will create two
function clones, one compiled with @option{-mcpu=power9} and another 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 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 @item unused
@cindex @code{unused} function attribute @cindex @code{unused} function attribute
......
...@@ -37,6 +37,12 @@ along with GCC; see the file COPYING3. If not see ...@@ -37,6 +37,12 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-ssa.h" #include "gimple-ssa.h"
#include "tree-phinodes.h" #include "tree-phinodes.h"
#include "ssa-iterators.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 /* This is used to carry information about basic blocks. It is
attached to the AUX field of the standard CFG block. */ attached to the AUX field of the standard CFG block. */
...@@ -858,6 +864,135 @@ sanitize_asan_mark_poison (void) ...@@ -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 unsigned int
pass_sanopt::execute (function *fun) pass_sanopt::execute (function *fun)
{ {
...@@ -891,6 +1026,9 @@ pass_sanopt::execute (function *fun) ...@@ -891,6 +1026,9 @@ pass_sanopt::execute (function *fun)
sanitize_asan_mark_poison (); sanitize_asan_mark_poison ();
} }
if (asan_sanitize_stack_p ())
sanitize_rewrite_addressable_params (fun);
bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
&& asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD; && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
......
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> 2017-07-03 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.dg/vect/bb-slp-pr65935.c: Expect SLP to be used in main * gcc.dg/vect/bb-slp-pr65935.c: Expect SLP to be used in main
......
// { 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.*" }
// { 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.*" }
// { 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.*" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment