From f6b9f2ffc190054ca8f4dad110d85613964d2006 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 23 Jan 2017 12:06:13 +0000 Subject: [PATCH] use-after-scope: handle writes to a poisoned variable 2017-01-23 Martin Liska * 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 Martin Liska * 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 --- gcc/ChangeLog | 21 +++++++++++++ gcc/asan.c | 19 +++++++----- gcc/asan.h | 2 ++ gcc/gimplify.c | 17 +++++++++-- gcc/internal-fn.c | 8 +++++ gcc/internal-fn.def | 1 + gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/g++.dg/asan/use-after-scope-5.C | 23 ++++++++++++++ .../gcc.dg/asan/use-after-scope-10.c | 22 ++++++++++++++ .../gcc.dg/asan/use-after-scope-11.c | 30 +++++++++++++++++++ gcc/tree-into-ssa.c | 27 ++++++++++++++++- gcc/tree-ssa-dce.c | 16 +++++++--- gcc/tree-ssa.c | 15 +++++++++- 13 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-5.C create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-10.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-11.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 34728a9e52f..5ab065fbcc7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2017-01-23 Jakub Jelinek + Martin Liska + + * 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 * asan.c (create_asan_shadow_var): New function. diff --git a/gcc/asan.c b/gcc/asan.c index fe117a6951a..486ebfdb6af 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -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); } } diff --git a/gcc/asan.h b/gcc/asan.h index 2895bdee645..57663977603 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -67,6 +67,8 @@ extern hash_set *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 { diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d382eea69f8..61a1ba5c7f9 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1206,8 +1206,21 @@ asan_poison_variables (hash_set *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. */ diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 45e4ce05b86..0d61375462d 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -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 diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 7b28b6722ff..fd25a952299 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bb60f696e03..0ebaae5035c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-01-23 Martin Liska + + * 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 * gcc.dg/asan/use-after-scope-3.c: Add additional flags. diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-5.C b/gcc/testsuite/g++.dg/asan/use-after-scope-5.C new file mode 100644 index 00000000000..7e28fc35e6d --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-5.C @@ -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(); +} diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-10.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-10.c new file mode 100644 index 00000000000..24de8cec1ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-10.c @@ -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.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-11.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-11.c new file mode 100644 index 00000000000..b3c4c9ec758 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-11.c @@ -0,0 +1,30 @@ +// { dg-do run } + +#include + +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; +} diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index c7df237d57f..22261c15dc2 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -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); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 4e51e699d49..5ebe57b0983 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -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)) diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index f1826b2c9c4..28020b003f8 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -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; } } -- 2.30.2