aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-11-22 21:04:45 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2013-11-22 21:04:45 +0100
commit59b36ecf239ba0164f55a2ac2cd37154d7963dd9 (patch)
treed11dfc57c47e4f7387f7f22a57a8e10b78aab3e1 /gcc
parent3e749749392a1d8e0db2ddc311239ccbc200a09f (diff)
downloadgcc-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/ChangeLog15
-rw-r--r--gcc/asan.c71
-rw-r--r--gcc/asan.h1
-rw-r--r--gcc/cgraph.h4
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/decl2.c26
-rw-r--r--gcc/sanitizer.def6
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c14
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
diff --git a/gcc/asan.c b/gcc/asan.c
index f68b173..677435e 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -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);
diff --git a/gcc/asan.h b/gcc/asan.h
index e564684..89cb5bb 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -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" } } */