diff options
author | Jakub Jelinek <jakub@redhat.com> | 2013-11-22 21:04:45 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2013-11-22 21:04:45 +0100 |
commit | 59b36ecf239ba0164f55a2ac2cd37154d7963dd9 (patch) | |
tree | d11dfc57c47e4f7387f7f22a57a8e10b78aab3e1 /gcc | |
parent | 3e749749392a1d8e0db2ddc311239ccbc200a09f (diff) | |
download | gcc-59b36ecf239ba0164f55a2ac2cd37154d7963dd9.zip gcc-59b36ecf239ba0164f55a2ac2cd37154d7963dd9.tar.gz gcc-59b36ecf239ba0164f55a2ac2cd37154d7963dd9.tar.bz2 |
sanitizer.def (BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, [...]): New.
* sanitizer.def (BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT,
BUILT_IN_ASAN_AFTER_DYNAMIC_INIT): New.
* asan.c (instrument_derefs): Handle also VAR_DECL loads/stores.
Don't instrument accesses to VAR_DECLs which are known to fit
into their bounds and the vars are known to have shadow bytes
indicating allowed access.
(asan_dynamic_init_call): New function.
(asan_add_global): If vnode->dynamically_initialized,
set __has_dynamic_init to 1 instead of 0.
(initialize_sanitizer_builtins): Add BT_FN_VOID_CONST_PTR var.
* asan.h (asan_dynamic_init_call): New prototype.
* cgraph.h (varpool_node): Add dynamically_initialized bitfield.
cp/
* decl2.c: Include asan.h.
(one_static_initialization_or_destruction): If -fsanitize=address,
init is non-NULL and guard is NULL, set
vnode->dynamically_initialized.
(do_static_initialization_or_destruction): Call
__asan_{before,after}_dynamic_init around the static initialization.
testsuite/
* c-c++-common/asan/no-redundant-instrumentation-1.c: Tweak to avoid
optimizing away some __asan_report* calls.
From-SVN: r205282
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/asan.c | 71 | ||||
-rw-r--r-- | gcc/asan.h | 1 | ||||
-rw-r--r-- | gcc/cgraph.h | 4 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 26 | ||||
-rw-r--r-- | gcc/sanitizer.def | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c | 14 |
9 files changed, 140 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index afc9664..334d082 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2013-11-22 Jakub Jelinek <jakub@redhat.com> + + * sanitizer.def (BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, + BUILT_IN_ASAN_AFTER_DYNAMIC_INIT): New. + * asan.c (instrument_derefs): Handle also VAR_DECL loads/stores. + Don't instrument accesses to VAR_DECLs which are known to fit + into their bounds and the vars are known to have shadow bytes + indicating allowed access. + (asan_dynamic_init_call): New function. + (asan_add_global): If vnode->dynamically_initialized, + set __has_dynamic_init to 1 instead of 0. + (initialize_sanitizer_builtins): Add BT_FN_VOID_CONST_PTR var. + * asan.h (asan_dynamic_init_call): New prototype. + * cgraph.h (varpool_node): Add dynamically_initialized bitfield. + 2013-11-22 Martin Jambor <mjambor@suse.cz> PR rtl-optimization/10474 @@ -224,7 +224,7 @@ along with GCC; see the file COPYING3. If not see // Name of the module where the global variable is declared. const void *__module_name; - // This is always set to NULL for now. + // 1 if it has dynamic initialization, 0 otherwise. uptr __has_dynamic_init; } @@ -1471,7 +1471,9 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, case COMPONENT_REF: case INDIRECT_REF: case MEM_REF: + case VAR_DECL: break; + /* FALLTHRU */ default: return; } @@ -1485,8 +1487,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, tree offset; enum machine_mode mode; int volatilep = 0, unsignedp = 0; - get_inner_reference (t, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, false); + tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, + &mode, &unsignedp, &volatilep, false); if (bitpos % (size_in_bytes * BITS_PER_UNIT) || bitsize != size_in_bytes * BITS_PER_UNIT) { @@ -1501,6 +1503,34 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, return; } + if (TREE_CODE (inner) == VAR_DECL + && offset == NULL_TREE + && bitpos >= 0 + && DECL_SIZE (inner) + && tree_fits_shwi_p (DECL_SIZE (inner)) + && bitpos + bitsize <= tree_to_shwi (DECL_SIZE (inner))) + { + if (DECL_THREAD_LOCAL_P (inner)) + return; + if (!TREE_STATIC (inner)) + { + /* Automatic vars in the current function will be always + accessible. */ + if (decl_function_context (inner) == current_function_decl) + return; + } + /* Always instrument external vars, they might be dynamically + initialized. */ + else if (!DECL_EXTERNAL (inner)) + { + /* For static vars if they are known not to be dynamically + initialized, they will be always accessible. */ + struct varpool_node *vnode = varpool_get_node (inner); + if (vnode && !vnode->dynamically_initialized) + return; + } + } + base = build_fold_addr_expr (t); if (!has_mem_ref_been_instrumented (base, size_in_bytes)) { @@ -1959,6 +1989,34 @@ transform_statements (void) } /* Build + __asan_before_dynamic_init (module_name) + or + __asan_after_dynamic_init () + call. */ + +tree +asan_dynamic_init_call (bool after_p) +{ + tree fn = builtin_decl_implicit (after_p + ? BUILT_IN_ASAN_AFTER_DYNAMIC_INIT + : BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT); + tree module_name_cst = NULL_TREE; + if (!after_p) + { + pretty_printer module_name_pp; + pp_string (&module_name_pp, main_input_filename); + + if (shadow_ptr_types[0] == NULL_TREE) + asan_init_shadow_ptr_types (); + module_name_cst = asan_pp_string (&module_name_pp); + module_name_cst = fold_convert (const_ptr_type_node, + module_name_cst); + } + + return build_call_expr (fn, after_p ? 0 : 1, module_name_cst); +} + +/* Build struct __asan_global { const void *__beg; @@ -2047,7 +2105,10 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v) fold_convert (const_ptr_type_node, str_cst)); CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, fold_convert (const_ptr_type_node, module_name_cst)); - CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0)); + struct varpool_node *vnode = varpool_get_node (decl); + int has_dynamic_init = vnode ? vnode->dynamically_initialized : 0; + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, + build_int_cst (uptr, has_dynamic_init)); init = build_constructor (type, vinner); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); } @@ -2064,6 +2125,8 @@ initialize_sanitizer_builtins (void) tree BT_FN_VOID = build_function_type_list (void_type_node, NULL_TREE); tree BT_FN_VOID_PTR = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); + tree BT_FN_VOID_CONST_PTR + = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE); tree BT_FN_VOID_PTR_PTR = build_function_type_list (void_type_node, ptr_type_node, ptr_type_node, NULL_TREE); @@ -26,6 +26,7 @@ extern void asan_finish_file (void); extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int); extern bool asan_protect_global (tree); extern void initialize_sanitizer_builtins (void); +extern tree asan_dynamic_init_call (bool); /* Alias set for accessing the shadow memory. */ extern alias_set_type asan_shadow_set; diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 15719fb..c6b35f9 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -532,6 +532,10 @@ public: /* Set when variable has statically initialized pointer or is a static bounds variable and needs initalization. */ unsigned need_bounds_init : 1; + + /* Set if the variable is dynamically initialized, except for + function local statics. */ + unsigned dynamically_initialized : 1; }; /* Every top level asm statement is put into a asm_node. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0a6ae93..479d919 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2013-11-22 Jakub Jelinek <jakub@redhat.com> + + * decl2.c: Include asan.h. + (one_static_initialization_or_destruction): If -fsanitize=address, + init is non-NULL and guard is NULL, set + vnode->dynamically_initialized. + (do_static_initialization_or_destruction): Call + __asan_{before,after}_dynamic_init around the static initialization. + 2013-11-22 Andrew MacLeod <amacleod@redhat.com> * class.c: Add required include files from gimple.h. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 06c32f3..0e37a5d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see #include "splay-tree.h" #include "langhooks.h" #include "c-family/c-ada-spec.h" +#include "asan.h" extern cpp_reader *parse_in; @@ -3461,7 +3462,15 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) if (initp) { if (init) - finish_expr_stmt (init); + { + finish_expr_stmt (init); + if (flag_sanitize & SANITIZE_ADDRESS) + { + struct varpool_node *vnode = varpool_get_node (decl); + if (vnode) + vnode->dynamically_initialized = 1; + } + } /* If we're using __cxa_atexit, register a function that calls the destructor for the object. */ @@ -3503,6 +3512,16 @@ do_static_initialization_or_destruction (tree vars, bool initp) tf_warning_or_error); finish_if_stmt_cond (cond, init_if_stmt); + /* To make sure dynamic construction doesn't access globals from other + compilation units where they might not be yet constructed, for + -fsanitize=address insert __asan_before_dynamic_init call that + prevents access to either all global variables that need construction + in other compilation units, or at least those that haven't been + initialized yet. Variables that need dynamic construction in + the current compilation unit are kept accessible. */ + if (flag_sanitize & SANITIZE_ADDRESS) + finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false)); + node = vars; do { tree decl = TREE_VALUE (node); @@ -3551,6 +3570,11 @@ do_static_initialization_or_destruction (tree vars, bool initp) } while (node); + /* Revert what __asan_before_dynamic_init did by calling + __asan_after_dynamic_init. */ + if (flag_sanitize & SANITIZE_ADDRESS) + finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/true)); + /* Finish up the init/destruct if-stmt body. */ finish_then_clause (init_if_stmt); finish_if_stmt (init_if_stmt); diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 9c59778..ad1248d 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -60,6 +60,12 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNREGISTER_GLOBALS, DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN, "__asan_handle_no_return", BT_FN_VOID, ATTR_TMPURE_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, + "__asan_before_dynamic_init", + BT_FN_VOID_CONST_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT, + "__asan_after_dynamic_init", + BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) /* Thread Sanitizer */ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7d895c5..a98a7b97 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-11-22 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/asan/no-redundant-instrumentation-1.c: Tweak to avoid + optimizing away some __asan_report* calls. + 2013-11-22 Martin Jambor <mjambor@suse.cz> * gcc.dg/pr10474.c: Also test ppc64. diff --git a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c index 6cf6441..fa52e0c 100644 --- a/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c +++ b/gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c @@ -6,7 +6,7 @@ /* { dg-do compile } */ /* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ -static char tab[4] = {0}; +extern char tab[4]; static int test0 () @@ -27,12 +27,14 @@ test0 () return t0 + t1; } -static int -test1 () +__attribute__((noinline, noclone)) static int +test1 (int i) { + char foo[4] = {}; + /*__builtin___asan_report_store1 called 1 time here to instrument the initialization. */ - char foo[4] = {1}; + foo[i] = 1; /*__builtin___asan_report_store1 called 2 times here to instrument the store to the memory region of tab. */ @@ -45,7 +47,7 @@ test1 () /* There are 2 calls to __builtin___asan_report_store1 and 2 calls to __builtin___asan_report_load1 to instrument the store to (subset of) the memory region of tab. */ - __builtin_memcpy (&tab[1], foo, 3); + __builtin_memcpy (&tab[1], foo + i, 3); /* This should not generate a __builtin___asan_report_load1 because the reference to tab[1] has been already instrumented above. */ @@ -58,7 +60,7 @@ test1 () int main () { - return test0 () && test1 (); + return test0 () && test1 (0); } /* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */ |