+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
// 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;
}
case COMPONENT_REF:
case INDIRECT_REF:
case MEM_REF:
+ case VAR_DECL:
break;
+ /* FALLTHRU */
default:
return;
}
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)
{
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))
{
}
/* 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;
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);
}
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);
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;
/* 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. */
+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.
#include "splay-tree.h"
#include "langhooks.h"
#include "c-family/c-ada-spec.h"
+#include "asan.h"
extern cpp_reader *parse_in;
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. */
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);
} 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);
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",
+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.
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
-static char tab[4] = {0};
+extern char tab[4];
static int
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. */
/* 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. */
int
main ()
{
- return test0 () && test1 ();
+ return test0 () && test1 (0);
}
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */