sanitizer.def (BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, [...]): New.
authorJakub Jelinek <jakub@redhat.com>
Fri, 22 Nov 2013 20:04:45 +0000 (21:04 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 22 Nov 2013 20:04:45 +0000 (21:04 +0100)
* 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

gcc/ChangeLog
gcc/asan.c
gcc/asan.h
gcc/cgraph.h
gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/sanitizer.def
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/asan/no-redundant-instrumentation-1.c

index afc9664..334d082 100644 (file)
@@ -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
index f68b173..677435e 100644 (file)
@@ -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);
index e564684..89cb5bb 100644 (file)
@@ -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;
index 15719fb..c6b35f9 100644 (file)
@@ -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.  */
index 0a6ae93..479d919 100644 (file)
@@ -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.
index 06c32f3..0e37a5d 100644 (file)
@@ -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);
index 9c59778..ad1248d 100644 (file)
@@ -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", 
index 7d895c5..a98a7b9 100644 (file)
@@ -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.
index 6cf6441..fa52e0c 100644 (file)
@@ -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" } } */