use-after-scope: handle writes to a poisoned variable

2017-01-23  Martin Liska  <mliska@suse.cz>

	* gcc.dg/asan/use-after-scope-10.c: New test.
	* gcc.dg/asan/use-after-scope-11.c: New test.
	* g++.dg/asan/use-after-scope-5.C: New test.
2017-01-23  Jakub Jelinek  <jakub@redhat.com>
	    Martin Liska  <mliska@suse.cz>

	* asan.h: Define ASAN_USE_AFTER_SCOPE_ATTRIBUTE.
	* asan.c (asan_expand_poison_ifn): Support stores and use
	appropriate ASAN report function.
	* internal-fn.c (expand_ASAN_POISON_USE): New function.
	* internal-fn.def (ASAN_POISON_USE): Declare.
	* tree-into-ssa.c (maybe_add_asan_poison_write): New function.
	(maybe_register_def): Create ASAN_POISON_USE when sanitizing.
	* tree-ssa-dce.c (eliminate_unnecessary_stmts): Remove
	ASAN_POISON calls w/o LHS.
	* tree-ssa.c (execute_update_addresses_taken): Create clobber
	for ASAN_MARK (UNPOISON, &x, ...) in order to prevent usage of a LHS
	from ASAN_MARK (POISON, &x, ...) coming to a PHI node.
	* gimplify.c (asan_poison_variables): Add attribute
	use_after_scope_memory to variables that really needs to live
	in memory.
	* tree-ssa.c (is_asan_mark_p): Do not rewrite into SSA when
	having the attribute.

From-SVN: r244793
This commit is contained in:
Martin Liska 2017-01-23 12:06:13 +00:00
parent a51368fad9
commit f6b9f2ffc1
13 changed files with 192 additions and 15 deletions

View File

@ -1,3 +1,24 @@
2017-01-23 Jakub Jelinek <jakub@redhat.com>
Martin Liska <mliska@suse.cz>
* asan.h: Define ASAN_USE_AFTER_SCOPE_ATTRIBUTE.
* asan.c (asan_expand_poison_ifn): Support stores and use
appropriate ASAN report function.
* internal-fn.c (expand_ASAN_POISON_USE): New function.
* internal-fn.def (ASAN_POISON_USE): Declare.
* tree-into-ssa.c (maybe_add_asan_poison_write): New function.
(maybe_register_def): Create ASAN_POISON_USE when sanitizing.
* tree-ssa-dce.c (eliminate_unnecessary_stmts): Remove
ASAN_POISON calls w/o LHS.
* tree-ssa.c (execute_update_addresses_taken): Create clobber
for ASAN_MARK (UNPOISON, &x, ...) in order to prevent usage of a LHS
from ASAN_MARK (POISON, &x, ...) coming to a PHI node.
* gimplify.c (asan_poison_variables): Add attribute
use_after_scope_memory to variables that really needs to live
in memory.
* tree-ssa.c (is_asan_mark_p): Do not rewrite into SSA when
having the attribute.
2017-01-23 Martin Liska <mliska@suse.cz>
* asan.c (create_asan_shadow_var): New function.

View File

@ -3094,6 +3094,8 @@ create_asan_shadow_var (tree var_decl,
return *slot;
}
/* Expand ASAN_POISON ifn. */
bool
asan_expand_poison_ifn (gimple_stmt_iterator *iter,
bool *need_commit_edge_insert,
@ -3107,8 +3109,8 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
return true;
}
tree shadow_var = create_asan_shadow_var (SSA_NAME_VAR (poisoned_var),
shadow_vars_mapping);
tree shadow_var = create_asan_shadow_var (SSA_NAME_VAR (poisoned_var),
shadow_vars_mapping);
bool recover_p;
if (flag_sanitize & SANITIZE_USER_ADDRESS)
@ -3122,16 +3124,16 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
ASAN_MARK_POISON),
build_fold_addr_expr (shadow_var), size);
use_operand_p use_p;
gimple *use;
imm_use_iterator imm_iter;
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, poisoned_var)
FOR_EACH_IMM_USE_STMT (use, imm_iter, poisoned_var)
{
gimple *use = USE_STMT (use_p);
if (is_gimple_debug (use))
continue;
int nargs;
tree fun = report_error_func (false, recover_p, tree_to_uhwi (size),
bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE);
tree fun = report_error_func (store_p, recover_p, tree_to_uhwi (size),
&nargs);
gcall *call = gimple_build_call (fun, 1,
@ -3160,7 +3162,10 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
else
{
gimple_stmt_iterator gsi = gsi_for_stmt (use);
gsi_insert_before (&gsi, call, GSI_NEW_STMT);
if (store_p)
gsi_replace (&gsi, call, true);
else
gsi_insert_before (&gsi, call, GSI_NEW_STMT);
}
}

View File

@ -67,6 +67,8 @@ extern hash_set <tree> *asan_used_labels;
#define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
#define ASAN_STACK_RETIRED_MAGIC 0x45e0360e
#define ASAN_USE_AFTER_SCOPE_ATTRIBUTE "use after scope memory"
/* Various flags for Asan builtins. */
enum asan_check_flags
{

View File

@ -1206,8 +1206,21 @@ asan_poison_variables (hash_set<tree> *variables, bool poison, gimple_seq *seq_p
sorted_variables.qsort (sort_by_decl_uid);
for (unsigned i = 0; i < sorted_variables.length (); i++)
asan_poison_variable (sorted_variables[i], poison, seq_p);
unsigned i;
tree var;
FOR_EACH_VEC_ELT (sorted_variables, i, var)
{
asan_poison_variable (var, poison, seq_p);
/* Add use_after_scope_memory attribute for the variable in order
to prevent re-written into SSA. */
if (!lookup_attribute (ASAN_USE_AFTER_SCOPE_ATTRIBUTE,
DECL_ATTRIBUTES (var)))
DECL_ATTRIBUTES (var)
= tree_cons (get_identifier (ASAN_USE_AFTER_SCOPE_ATTRIBUTE),
integer_one_node,
DECL_ATTRIBUTES (var));
}
}
/* Gimplify a BIND_EXPR. Just voidify and recurse. */

View File

@ -388,6 +388,14 @@ expand_ASAN_POISON (internal_fn, gcall *)
gcc_unreachable ();
}
/* This should get expanded in the sanopt pass. */
static void
expand_ASAN_POISON_USE (internal_fn, gcall *)
{
gcc_unreachable ();
}
/* This should get expanded in the tsan pass. */
static void

View File

@ -168,6 +168,7 @@ DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...")
DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, ".R..")
DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
DEF_INTERNAL_FN (ASAN_POISON_USE, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
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)

View File

@ -1,3 +1,9 @@
2017-01-23 Martin Liska <mliska@suse.cz>
* gcc.dg/asan/use-after-scope-10.c: New test.
* gcc.dg/asan/use-after-scope-11.c: New test.
* g++.dg/asan/use-after-scope-5.C: New test.
2017-01-23 Martin Liska <mliska@suse.cz>
* gcc.dg/asan/use-after-scope-3.c: Add additional flags.

View File

@ -0,0 +1,23 @@
// { dg-do run }
int *
__attribute__((optimize(("-O0"))))
fn1 (int *a)
{
return a;
}
void
fn2 ()
{
for (int i = 0; i < 10; i++)
{
int *a;
(a) = fn1 (a);
}
}
int main()
{
fn2();
}

View File

@ -0,0 +1,22 @@
// { dg-do run }
// { dg-shouldfail "asan" }
// { dg-additional-options "-O2 -fdump-tree-asan1" }
int
main (int argc, char **argv)
{
int *ptr = 0;
{
int a;
ptr = &a;
*ptr = 12345;
}
*ptr = 12345;
return *ptr;
}
// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
// { dg-output "WRITE of size .*" }
// { dg-output ".*'a' <== Memory access at offset \[0-9\]* is inside this variable.*" }

View File

@ -0,0 +1,30 @@
// { dg-do run }
#include <string.h>
char cc;
char ptr[] = "sparta2";
void get(char **x)
{
*x = ptr;
}
int main()
{
char *here = &cc;
for (;;)
{
next_line:
if (here == NULL)
__builtin_abort();
get (&here);
if (strcmp (here, "sparta") == 0)
goto next_line;
else if (strcmp (here, "sparta2") == 0)
break;
}
return 0;
}

View File

@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa.h"
#include "domwalk.h"
#include "statistics.h"
#include "asan.h"
#define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
@ -1807,6 +1808,26 @@ maybe_replace_use_in_debug_stmt (use_operand_p use_p)
}
/* If DEF has x_5 = ASAN_POISON () as its current def, add
ASAN_POISON_USE (x_5) stmt before GSI to denote the stmt writes into
a poisoned (out of scope) variable. */
static void
maybe_add_asan_poison_write (tree def, gimple_stmt_iterator *gsi)
{
tree cdef = get_current_def (def);
if (cdef != NULL
&& TREE_CODE (cdef) == SSA_NAME
&& gimple_call_internal_p (SSA_NAME_DEF_STMT (cdef), IFN_ASAN_POISON))
{
gcall *call
= gimple_build_call_internal (IFN_ASAN_POISON_USE, 1, cdef);
gimple_set_location (call, gimple_location (gsi_stmt (*gsi)));
gsi_insert_before (gsi, call, GSI_SAME_STMT);
}
}
/* If the operand pointed to by DEF_P is an SSA name in NEW_SSA_NAMES
or OLD_SSA_NAMES, or if it is a symbol marked for renaming,
register it as the current definition for the names replaced by
@ -1837,7 +1858,11 @@ maybe_register_def (def_operand_p def_p, gimple *stmt,
def = get_or_create_ssa_default_def (cfun, sym);
}
else
def = make_ssa_name (def, stmt);
{
if (asan_sanitize_use_after_scope ())
maybe_add_asan_poison_write (def, &gsi);
def = make_ssa_name (def, stmt);
}
SET_DEF (def_p, def);
tree tracked_var = target_for_debug_bind (sym);

View File

@ -1367,10 +1367,18 @@ eliminate_unnecessary_stmts (void)
update_stmt (stmt);
release_ssa_name (name);
/* GOMP_SIMD_LANE without lhs is not needed. */
if (gimple_call_internal_p (stmt)
&& gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE)
remove_dead_stmt (&gsi, bb);
/* GOMP_SIMD_LANE or ASAN_POISON without lhs is not
needed. */
if (gimple_call_internal_p (stmt))
switch (gimple_call_internal_fn (stmt))
{
case IFN_GOMP_SIMD_LANE:
case IFN_ASAN_POISON:
remove_dead_stmt (&gsi, bb);
break;
default:
break;
}
}
else if (gimple_call_internal_p (stmt))
switch (gimple_call_internal_fn (stmt))

View File

@ -1590,6 +1590,10 @@ is_asan_mark_p (gimple *stmt)
&& VAR_P (TREE_OPERAND (addr, 0)))
{
tree var = TREE_OPERAND (addr, 0);
if (lookup_attribute (ASAN_USE_AFTER_SCOPE_ATTRIBUTE,
DECL_ATTRIBUTES (var)))
return false;
unsigned addressable = TREE_ADDRESSABLE (var);
TREE_ADDRESSABLE (var) = 0;
bool r = is_gimple_reg (var);
@ -1911,7 +1915,16 @@ execute_update_addresses_taken (void)
gsi_replace (&gsi, call, GSI_SAME_STMT);
}
else
gsi_remove (&gsi, true);
{
/* In ASAN_MARK (UNPOISON, &b, ...) the variable
is uninitialized. Avoid dependencies on
previous out of scope value. */
tree clobber
= build_constructor (TREE_TYPE (var), NULL);
TREE_THIS_VOLATILE (clobber) = 1;
gimple *g = gimple_build_assign (var, clobber);
gsi_replace (&gsi, g, GSI_SAME_STMT);
}
continue;
}
}