/* 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.
#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"
#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"
#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"
#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"
#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.
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.
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. */
set_asan_shadow_offset (const char *val)
{
char *endp;
-
+
errno = 0;
#ifdef HAVE_LONG_LONG
asan_shadow_offset_value = strtoull (val, &endp, 0);
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
/* 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. */
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;
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. */
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. */
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))
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);
{
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);
{
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);
{
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
is_store);
is_instrumented = true;
}
-
+
if (gimple_assign_load_p (s))
{
ref_expr = gimple_assign_rhs1 (s);
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);
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;
}
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);
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);
&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);
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);