re PR c++/65977 (Constexpr should be allowed in declaration of friend template specia...
[gcc.git] / gcc / asan.c
index a976455c6e641607d2db8f90a2f678d41325c1a4..5fac24703231867f0be63314a8927f8821afbde7 100644 (file)
@@ -1,5 +1,5 @@
 /* AddressSanitizer, a fast memory error detector.
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2015 Free Software Foundation, Inc.
    Contributed by Kostya Serebryany <kcc@google.com>
 
 This file is part of GCC.
@@ -22,16 +22,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
 #include "tree.h"
-#include "hash-table.h"
+#include "fold-const.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
 #include "tm.h"
 #include "hard-reg-set.h"
-#include "input.h"
 #include "function.h"
 #include "dominance.h"
 #include "cfg.h"
@@ -40,8 +38,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "gimple-expr.h"
-#include "is-a.h"
-#include "inchash.h"
 #include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
@@ -49,9 +45,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
-#include "hash-map.h"
-#include "plugin-api.h"
-#include "ipa-ref.h"
 #include "cgraph.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
@@ -59,6 +52,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "gimple-pretty-print.h"
 #include "target.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
 #include "insn-codes.h"
 #include "optabs.h"
@@ -71,6 +72,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ubsan.h"
 #include "params.h"
 #include "builtins.h"
+#include "fnmatch.h"
 
 /* AddressSanitizer finds out-of-bounds and use-after-free bugs
    with <2x slowdown on average.
@@ -158,7 +160,7 @@ along with GCC; see the file COPYING3.  If not see
 
        where '(...){n}' means the content inside the parenthesis occurs 'n'
        times, with 'n' being the number of variables on the stack.
-     
+
      3/ The following 8 bytes contain the PC of the current function which
      will be used by the run-time library to print an error message.
 
@@ -255,6 +257,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static unsigned HOST_WIDE_INT asan_shadow_offset_value;
 static bool asan_shadow_offset_computed;
+static vec<char *> sanitized_sections;
 
 /* Sets shadow offset to value in string VAL.  */
 
@@ -262,7 +265,7 @@ bool
 set_asan_shadow_offset (const char *val)
 {
   char *endp;
-  
+
   errno = 0;
 #ifdef HAVE_LONG_LONG
   asan_shadow_offset_value = strtoull (val, &endp, 0);
@@ -277,6 +280,40 @@ set_asan_shadow_offset (const char *val)
   return true;
 }
 
+/* Set list of user-defined sections that need to be sanitized.  */
+
+void
+set_sanitized_sections (const char *sections)
+{
+  char *pat;
+  unsigned i;
+  FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
+    free (pat);
+  sanitized_sections.truncate (0);
+
+  for (const char *s = sections; *s; )
+    {
+      const char *end;
+      for (end = s; *end && *end != ','; ++end);
+      size_t len = end - s;
+      sanitized_sections.safe_push (xstrndup (s, len));
+      s = *end ? end + 1 : end;
+    }
+}
+
+/* Checks whether section SEC should be sanitized.  */
+
+static bool
+section_sanitized_p (const char *sec)
+{
+  char *pat;
+  unsigned i;
+  FOR_EACH_VEC_ELT (sanitized_sections, i, pat)
+    if (fnmatch (pat, sec, FNM_PERIOD) == 0)
+      return true;
+  return false;
+}
+
 /* Returns Asan shadow offset.  */
 
 static unsigned HOST_WIDE_INT
@@ -319,23 +356,24 @@ struct asan_mem_ref
 
   /* The size of the access.  */
   HOST_WIDE_INT access_size;
-};
 
-static alloc_pool asan_mem_ref_alloc_pool;
+  /* Pool allocation new operator.  */
+  inline void *operator new (size_t)
+  {
+    return pool.allocate ();
+  }
 
-/* This creates the alloc pool used to store the instances of
-   asan_mem_ref that are stored in the hash table asan_mem_ref_ht.  */
+  /* Delete operator utilizing pool allocation.  */
+  inline void operator delete (void *ptr)
+  {
+    pool.remove ((asan_mem_ref *) ptr);
+  }
 
-static alloc_pool
-asan_mem_ref_get_alloc_pool ()
-{
-  if (asan_mem_ref_alloc_pool == NULL)
-    asan_mem_ref_alloc_pool = create_alloc_pool ("asan_mem_ref",
-                                                sizeof (asan_mem_ref),
-                                                10);
-  return asan_mem_ref_alloc_pool;
-    
-}
+  /* Memory allocation pool.  */
+  static pool_allocator<asan_mem_ref> pool;
+};
+
+pool_allocator<asan_mem_ref> asan_mem_ref::pool ("asan_mem_ref", 10);
 
 /* Initializes an instance of asan_mem_ref.  */
 
@@ -355,8 +393,7 @@ asan_mem_ref_init (asan_mem_ref *ref, tree start, HOST_WIDE_INT access_size)
 static asan_mem_ref*
 asan_mem_ref_new (tree start, HOST_WIDE_INT access_size)
 {
-  asan_mem_ref *ref =
-    (asan_mem_ref *) pool_alloc (asan_mem_ref_get_alloc_pool ());
+  asan_mem_ref *ref = new asan_mem_ref;
 
   asan_mem_ref_init (ref, start, access_size);
   return ref;
@@ -387,14 +424,10 @@ asan_mem_ref_get_end (const asan_mem_ref *ref, tree len)
   return asan_mem_ref_get_end (ref->start, len);
 }
 
-struct asan_mem_ref_hasher
-  : typed_noop_remove <asan_mem_ref>
+struct asan_mem_ref_hasher : nofree_ptr_hash <asan_mem_ref>
 {
-  typedef asan_mem_ref value_type;
-  typedef asan_mem_ref compare_type;
-
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const asan_mem_ref *);
+  static inline bool equal (const asan_mem_ref *, const asan_mem_ref *);
 };
 
 /* Hash a memory reference.  */
@@ -448,11 +481,7 @@ free_mem_ref_resources ()
   delete asan_mem_ref_ht;
   asan_mem_ref_ht = NULL;
 
-  if (asan_mem_ref_alloc_pool)
-    {
-      free_alloc_pool (asan_mem_ref_alloc_pool);
-      asan_mem_ref_alloc_pool = NULL;
-    }
+  asan_mem_ref::pool.release ();
 }
 
 /* Return true iff the memory reference REF has been instrumented.  */
@@ -1348,14 +1377,17 @@ asan_protect_global (tree decl)
         the var that is selected by the linker will have
         padding or not.  */
       || DECL_ONE_ONLY (decl)
-      /* Similarly for common vars.  People can use -fno-common.  */
+      /* Similarly for common vars.  People can use -fno-common.
+        Note: Linux kernel is built with -fno-common, so we do instrument
+        globals there even if it is C.  */
       || (DECL_COMMON (decl) && TREE_PUBLIC (decl))
       /* Don't protect if using user section, often vars placed
         into user section from multiple TUs are then assumed
         to be an array of such vars, putting padding in there
         breaks this assumption.  */
       || (DECL_SECTION_NAME (decl) != NULL
-         && !symtab_node::get (decl)->implicit_section)
+         && !symtab_node::get (decl)->implicit_section
+         && !section_sanitized_p (DECL_SECTION_NAME (decl)))
       || DECL_SIZE (decl) == 0
       || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
       || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
@@ -1585,25 +1617,25 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
   gimple g;
 
   t = build_int_cst (uintptr_type, ASAN_SHADOW_SHIFT);
-  g = gimple_build_assign_with_ops (RSHIFT_EXPR, make_ssa_name (uintptr_type),
-                                   base_addr, t);
+  g = gimple_build_assign (make_ssa_name (uintptr_type), RSHIFT_EXPR,
+                          base_addr, t);
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
   t = build_int_cst (uintptr_type, asan_shadow_offset ());
-  g = gimple_build_assign_with_ops (PLUS_EXPR, make_ssa_name (uintptr_type),
-                                   gimple_assign_lhs (g), t);
+  g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
+                          gimple_assign_lhs (g), t);
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
-  g = gimple_build_assign_with_ops (NOP_EXPR, make_ssa_name (shadow_ptr_type),
-                                   gimple_assign_lhs (g));
+  g = gimple_build_assign (make_ssa_name (shadow_ptr_type), NOP_EXPR,
+                          gimple_assign_lhs (g));
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
 
   t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
              build_int_cst (shadow_ptr_type, 0));
-  g = gimple_build_assign_with_ops (MEM_REF, make_ssa_name (shadow_type), t);
+  g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
   gimple_set_location (g, location);
   gsi_insert_after (gsi, g, GSI_NEW_STMT);
   return gimple_assign_lhs (g);
@@ -1618,9 +1650,8 @@ maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
 {
   if (TREE_CODE (base) == SSA_NAME)
     return base;
-  gimple g
-    = gimple_build_assign_with_ops (TREE_CODE (base),
-                                   make_ssa_name (TREE_TYPE (base)), base);
+  gimple g = gimple_build_assign (make_ssa_name (TREE_TYPE (base)),
+                                 TREE_CODE (base), base);
   gimple_set_location (g, loc);
   if (before_p)
     gsi_insert_before (iter, g, GSI_SAME_STMT);
@@ -1638,10 +1669,8 @@ maybe_cast_to_ptrmode (location_t loc, tree len, gimple_stmt_iterator *iter,
 {
   if (ptrofftype_p (len))
     return len;
-  gimple g
-    = gimple_build_assign_with_ops (NOP_EXPR,
-                                   make_ssa_name (pointer_sized_int_node),
-                                   len);
+  gimple g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                 NOP_EXPR, len);
   gimple_set_location (g, loc);
   if (before_p)
     gsi_insert_before (iter, g, GSI_SAME_STMT);
@@ -1804,6 +1833,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
        return;
+      if (!ASAN_GLOBALS && is_global_var (inner))
+        return;
       if (!TREE_STATIC (inner))
        {
          /* Automatic vars in the current function will be always
@@ -1980,7 +2011,7 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
                         is_store);
       is_instrumented = true;
     }
+
   if (gimple_assign_load_p (s))
     {
       ref_expr = gimple_assign_rhs1 (s);
@@ -2451,6 +2482,13 @@ asan_finish_file (void)
      nor after .LASAN* array.  */
   flag_sanitize &= ~SANITIZE_ADDRESS;
 
+  /* For user-space we want asan constructors to run first.
+     Linux kernel does not support priorities other than default, and the only
+     other user of constructors is coverage. So we run with the default
+     priority.  */
+  int priority = flag_sanitize & SANITIZE_USER_ADDRESS
+                 ? MAX_RESERVED_INIT_PRIORITY - 1 : DEFAULT_INIT_PRIORITY;
+
   if (flag_sanitize & SANITIZE_USER_ADDRESS)
     {
       tree fn = builtin_decl_implicit (BUILT_IN_ASAN_INIT);
@@ -2506,12 +2544,10 @@ asan_finish_file (void)
                                                 build_fold_addr_expr (var),
                                                 gcount_tree),
                                &dtor_statements);
-      cgraph_build_static_cdtor ('D', dtor_statements,
-                                MAX_RESERVED_INIT_PRIORITY - 1);
+      cgraph_build_static_cdtor ('D', dtor_statements, priority);
     }
   if (asan_ctor_statements)
-    cgraph_build_static_cdtor ('I', asan_ctor_statements,
-                              MAX_RESERVED_INIT_PRIORITY - 1);
+    cgraph_build_static_cdtor ('I', asan_ctor_statements, priority);
   flag_sanitize |= SANITIZE_ADDRESS;
 }
 
@@ -2542,10 +2578,8 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
   if (use_calls)
     {
       /* Instrument using callbacks.  */
-      gimple g
-       = gimple_build_assign_with_ops (NOP_EXPR,
-                                       make_ssa_name (pointer_sized_int_node),
-                                       base);
+      gimple g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                     NOP_EXPR, base);
       gimple_set_location (g, loc);
       gsi_insert_before (iter, g, GSI_SAME_STMT);
       tree base_addr = gimple_assign_lhs (g);
@@ -2557,9 +2591,8 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
       else
        {
          gcc_assert (nargs == 2);
-         g = gimple_build_assign_with_ops (NOP_EXPR,
-                                           make_ssa_name (pointer_sized_int_node),
-                                           len);
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  NOP_EXPR, len);
          gimple_set_location (g, loc);
          gsi_insert_before (iter, g, GSI_SAME_STMT);
          tree sz_arg = gimple_assign_lhs (g);
@@ -2616,9 +2649,8 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
                                  &then_bb,
                                  &else_bb);
 
-  g = gimple_build_assign_with_ops (NOP_EXPR,
-                                   make_ssa_name (pointer_sized_int_node),
-                                   base);
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                          NOP_EXPR, base);
   gimple_set_location (g, loc);
   gsi_insert_before (&gsi, g, GSI_NEW_STMT);
   tree base_addr = gimple_assign_lhs (g);
@@ -2670,17 +2702,14 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
        check first and last byte.  */
       if (size_in_bytes == -1)
        {
-         g = gimple_build_assign_with_ops (MINUS_EXPR,
-                                           make_ssa_name (pointer_sized_int_node),
-                                           len,
-                                           build_int_cst (pointer_sized_int_node, 1));
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  MINUS_EXPR, len,
+                                  build_int_cst (pointer_sized_int_node, 1));
          gimple_set_location (g, loc);
          gsi_insert_after (&gsi, g, GSI_NEW_STMT);
          tree last = gimple_assign_lhs (g);
-         g = gimple_build_assign_with_ops (PLUS_EXPR,
-                                           make_ssa_name (pointer_sized_int_node),
-                                           base_addr,
-                                           last);
+         g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+                                  PLUS_EXPR, base_addr, last);
          gimple_set_location (g, loc);
          gsi_insert_after (&gsi, g, GSI_NEW_STMT);
          tree base_end_addr = gimple_assign_lhs (g);