Commit 59b36ecf by Jakub Jelinek Committed by Jakub Jelinek

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
parent 3e749749
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> 2013-11-22 Martin Jambor <mjambor@suse.cz>
PR rtl-optimization/10474 PR rtl-optimization/10474
...@@ -224,7 +224,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -224,7 +224,7 @@ along with GCC; see the file COPYING3. If not see
// Name of the module where the global variable is declared. // Name of the module where the global variable is declared.
const void *__module_name; const void *__module_name;
// This is always set to NULL for now. // 1 if it has dynamic initialization, 0 otherwise.
uptr __has_dynamic_init; uptr __has_dynamic_init;
} }
...@@ -1471,7 +1471,9 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, ...@@ -1471,7 +1471,9 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
case COMPONENT_REF: case COMPONENT_REF:
case INDIRECT_REF: case INDIRECT_REF:
case MEM_REF: case MEM_REF:
case VAR_DECL:
break; break;
/* FALLTHRU */
default: default:
return; return;
} }
...@@ -1485,8 +1487,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, ...@@ -1485,8 +1487,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
tree offset; tree offset;
enum machine_mode mode; enum machine_mode mode;
int volatilep = 0, unsignedp = 0; int volatilep = 0, unsignedp = 0;
get_inner_reference (t, &bitsize, &bitpos, &offset, tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset,
&mode, &unsignedp, &volatilep, false); &mode, &unsignedp, &volatilep, false);
if (bitpos % (size_in_bytes * BITS_PER_UNIT) if (bitpos % (size_in_bytes * BITS_PER_UNIT)
|| bitsize != 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, ...@@ -1501,6 +1503,34 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
return; 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); base = build_fold_addr_expr (t);
if (!has_mem_ref_been_instrumented (base, size_in_bytes)) if (!has_mem_ref_been_instrumented (base, size_in_bytes))
{ {
...@@ -1959,6 +1989,34 @@ transform_statements (void) ...@@ -1959,6 +1989,34 @@ transform_statements (void)
} }
/* Build /* 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 struct __asan_global
{ {
const void *__beg; const void *__beg;
...@@ -2047,7 +2105,10 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v) ...@@ -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)); fold_convert (const_ptr_type_node, str_cst));
CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
fold_convert (const_ptr_type_node, module_name_cst)); 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); init = build_constructor (type, vinner);
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
} }
...@@ -2064,6 +2125,8 @@ initialize_sanitizer_builtins (void) ...@@ -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 = build_function_type_list (void_type_node, NULL_TREE);
tree BT_FN_VOID_PTR tree BT_FN_VOID_PTR
= build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); = 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 tree BT_FN_VOID_PTR_PTR
= build_function_type_list (void_type_node, ptr_type_node, = build_function_type_list (void_type_node, ptr_type_node,
ptr_type_node, NULL_TREE); ptr_type_node, NULL_TREE);
......
...@@ -26,6 +26,7 @@ extern void asan_finish_file (void); ...@@ -26,6 +26,7 @@ extern void asan_finish_file (void);
extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int); extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int);
extern bool asan_protect_global (tree); extern bool asan_protect_global (tree);
extern void initialize_sanitizer_builtins (void); extern void initialize_sanitizer_builtins (void);
extern tree asan_dynamic_init_call (bool);
/* Alias set for accessing the shadow memory. */ /* Alias set for accessing the shadow memory. */
extern alias_set_type asan_shadow_set; extern alias_set_type asan_shadow_set;
......
...@@ -532,6 +532,10 @@ public: ...@@ -532,6 +532,10 @@ public:
/* Set when variable has statically initialized pointer /* Set when variable has statically initialized pointer
or is a static bounds variable and needs initalization. */ or is a static bounds variable and needs initalization. */
unsigned need_bounds_init : 1; 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. */ /* Every top level asm statement is put into a asm_node. */
......
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> 2013-11-22 Andrew MacLeod <amacleod@redhat.com>
* class.c: Add required include files from gimple.h. * class.c: Add required include files from gimple.h.
......
...@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "splay-tree.h" #include "splay-tree.h"
#include "langhooks.h" #include "langhooks.h"
#include "c-family/c-ada-spec.h" #include "c-family/c-ada-spec.h"
#include "asan.h"
extern cpp_reader *parse_in; extern cpp_reader *parse_in;
...@@ -3461,7 +3462,15 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) ...@@ -3461,7 +3462,15 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp)
if (initp) if (initp)
{ {
if (init) 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 /* If we're using __cxa_atexit, register a function that calls the
destructor for the object. */ destructor for the object. */
...@@ -3503,6 +3512,16 @@ do_static_initialization_or_destruction (tree vars, bool initp) ...@@ -3503,6 +3512,16 @@ do_static_initialization_or_destruction (tree vars, bool initp)
tf_warning_or_error); tf_warning_or_error);
finish_if_stmt_cond (cond, init_if_stmt); 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; node = vars;
do { do {
tree decl = TREE_VALUE (node); tree decl = TREE_VALUE (node);
...@@ -3551,6 +3570,11 @@ do_static_initialization_or_destruction (tree vars, bool initp) ...@@ -3551,6 +3570,11 @@ do_static_initialization_or_destruction (tree vars, bool initp)
} while (node); } 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 up the init/destruct if-stmt body. */
finish_then_clause (init_if_stmt); finish_then_clause (init_if_stmt);
finish_if_stmt (init_if_stmt); finish_if_stmt (init_if_stmt);
......
...@@ -60,6 +60,12 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNREGISTER_GLOBALS, ...@@ -60,6 +60,12 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNREGISTER_GLOBALS,
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN, DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_HANDLE_NO_RETURN,
"__asan_handle_no_return", "__asan_handle_no_return",
BT_FN_VOID, ATTR_TMPURE_NOTHROW_LEAF_LIST) 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 */ /* Thread Sanitizer */
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
......
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> 2013-11-22 Martin Jambor <mjambor@suse.cz>
* gcc.dg/pr10474.c: Also test ppc64. * gcc.dg/pr10474.c: Also test ppc64.
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ /* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
static char tab[4] = {0}; extern char tab[4];
static int static int
test0 () test0 ()
...@@ -27,12 +27,14 @@ test0 () ...@@ -27,12 +27,14 @@ test0 ()
return t0 + t1; return t0 + t1;
} }
static int __attribute__((noinline, noclone)) static int
test1 () test1 (int i)
{ {
char foo[4] = {};
/*__builtin___asan_report_store1 called 1 time here to instrument /*__builtin___asan_report_store1 called 1 time here to instrument
the initialization. */ the initialization. */
char foo[4] = {1}; foo[i] = 1;
/*__builtin___asan_report_store1 called 2 times here to instrument /*__builtin___asan_report_store1 called 2 times here to instrument
the store to the memory region of tab. */ the store to the memory region of tab. */
...@@ -45,7 +47,7 @@ test1 () ...@@ -45,7 +47,7 @@ test1 ()
/* There are 2 calls to __builtin___asan_report_store1 and 2 calls /* There are 2 calls to __builtin___asan_report_store1 and 2 calls
to __builtin___asan_report_load1 to instrument the store to to __builtin___asan_report_load1 to instrument the store to
(subset of) the memory region of tab. */ (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 /* This should not generate a __builtin___asan_report_load1 because
the reference to tab[1] has been already instrumented above. */ the reference to tab[1] has been already instrumented above. */
...@@ -58,7 +60,7 @@ test1 () ...@@ -58,7 +60,7 @@ test1 ()
int int
main () main ()
{ {
return test0 () && test1 (); return test0 () && test1 (0);
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */
......
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