mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-08 06:50:27 +08:00
Don't inline GCC memory builtins if ASan is enabled.
gcc/ 2014-10-28 Max Ostapenko <m.ostapenko@partner.samsung.com> * asan.h (asan_intercepted_p): New function. * asan.c (asan_mem_ref_hasher::hash): Remove MEM_REF access size from hash value construction. Call iterative_hash_expr instead of explicit hash building. (asan_mem_ref_hasher::equal): Change condition. (has_mem_ref_been_instrumented): Likewise. (update_mem_ref_hash_table): Likewise. (maybe_update_mem_ref_hash_table): New function. (instrument_strlen_call): Removed. (get_mem_refs_of_builtin_call): Handle new parameter. (instrument_builtin_call): Call maybe_update_mem_ref_hash_table instead of instrument_mem_region_access if intercepted_p is true. (instrument_mem_region_access): Instrument only base with len instead of base and end with 1. (build_check_stmt): Remove start_instrumented and end_instrumented parameters. (enum asan_check_flags): Remove ASAN_CHECK_START_INSTRUMENTED and ASAN_CHECK_END_INSTRUMENTED. Change ASAN_CHECK_LAST. (asan_expand_check_ifn): Remove start_instrumented and end_instrumented. * builtins.c (expand_builtin): Include asan.h. Don't expand string/memory builtin functions that have interceptors if ASan is enabled. gcc/testsuite/ * c-c++-common/asan/no-redundant-instrumentation-1.c: Updated test. * c-c++-common/asan/no-redundant-instrumentation-4.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-5.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-6.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-7.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-8.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-2.c: Removed. * c-c++-common/asan/no-redundant-instrumentation-9.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-10.c: New test. * c-c++-common/asan/no-redundant-instrumentation-11.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-12.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-13.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-14.c: Likewise. * c-c++-common/asan/no-redundant-instrumentation-15.c: Likewise. * c-c++-common/asan/pr63638.c: Likewise. From-SVN: r216783
This commit is contained in:
parent
9ccaac1188
commit
bdea98ca2e
@ -1,3 +1,27 @@
|
||||
2014-10-28 Max Ostapenko <m.ostapenko@partner.samsung.com>
|
||||
|
||||
* asan.h (asan_intercepted_p): New function.
|
||||
* asan.c (asan_mem_ref_hasher::hash): Remove MEM_REF access size from
|
||||
hash value construction. Call iterative_hash_expr instead of explicit
|
||||
hash building.
|
||||
(asan_mem_ref_hasher::equal): Change condition.
|
||||
(has_mem_ref_been_instrumented): Likewise.
|
||||
(update_mem_ref_hash_table): Likewise.
|
||||
(maybe_update_mem_ref_hash_table): New function.
|
||||
(instrument_strlen_call): Removed.
|
||||
(get_mem_refs_of_builtin_call): Handle new parameter.
|
||||
(instrument_builtin_call): Call maybe_update_mem_ref_hash_table instead
|
||||
of instrument_mem_region_access if intercepted_p is true.
|
||||
(instrument_mem_region_access): Instrument only base with len instead of
|
||||
base and end with 1.
|
||||
(build_check_stmt): Remove start_instrumented and end_instrumented
|
||||
parameters.
|
||||
(enum asan_check_flags): Remove ASAN_CHECK_START_INSTRUMENTED and
|
||||
ASAN_CHECK_END_INSTRUMENTED. Change ASAN_CHECK_LAST.
|
||||
(asan_expand_check_ifn): Remove start_instrumented and end_instrumented.
|
||||
* builtins.c (expand_builtin): Include asan.h. Don't expand string/memory
|
||||
builtin functions that have interceptors if ASan is enabled.
|
||||
|
||||
2014-10-28 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR middle-end/63665
|
||||
|
324
gcc/asan.c
324
gcc/asan.c
@ -301,9 +301,7 @@ enum asan_check_flags
|
||||
ASAN_CHECK_STORE = 1 << 0,
|
||||
ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
|
||||
ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
|
||||
ASAN_CHECK_START_INSTRUMENTED = 1 << 3,
|
||||
ASAN_CHECK_END_INSTRUMENTED = 1 << 4,
|
||||
ASAN_CHECK_LAST
|
||||
ASAN_CHECK_LAST = 1 << 3
|
||||
};
|
||||
|
||||
/* Hashtable support for memory references used by gimple
|
||||
@ -400,10 +398,7 @@ struct asan_mem_ref_hasher
|
||||
inline hashval_t
|
||||
asan_mem_ref_hasher::hash (const asan_mem_ref *mem_ref)
|
||||
{
|
||||
inchash::hash hstate;
|
||||
inchash::add_expr (mem_ref->start, hstate);
|
||||
hstate.add_wide_int (mem_ref->access_size);
|
||||
return hstate.end ();
|
||||
return iterative_hash_expr (mem_ref->start, 0);
|
||||
}
|
||||
|
||||
/* Compare two memory references. We accept the length of either
|
||||
@ -413,8 +408,7 @@ inline bool
|
||||
asan_mem_ref_hasher::equal (const asan_mem_ref *m1,
|
||||
const asan_mem_ref *m2)
|
||||
{
|
||||
return (m1->access_size == m2->access_size
|
||||
&& operand_equal_p (m1->start, m2->start, 0));
|
||||
return operand_equal_p (m1->start, m2->start, 0);
|
||||
}
|
||||
|
||||
static hash_table<asan_mem_ref_hasher> *asan_mem_ref_ht;
|
||||
@ -465,7 +459,8 @@ has_mem_ref_been_instrumented (tree ref, HOST_WIDE_INT access_size)
|
||||
asan_mem_ref r;
|
||||
asan_mem_ref_init (&r, ref, access_size);
|
||||
|
||||
return (get_mem_ref_hash_table ()->find (&r) != NULL);
|
||||
asan_mem_ref *saved_ref = get_mem_ref_hash_table ()->find (&r);
|
||||
return saved_ref && saved_ref->access_size >= access_size;
|
||||
}
|
||||
|
||||
/* Return true iff the memory reference REF has been instrumented. */
|
||||
@ -482,19 +477,11 @@ has_mem_ref_been_instrumented (const asan_mem_ref *ref)
|
||||
static bool
|
||||
has_mem_ref_been_instrumented (const asan_mem_ref *ref, tree len)
|
||||
{
|
||||
/* First let's see if the address of the beginning of REF has been
|
||||
instrumented. */
|
||||
if (!has_mem_ref_been_instrumented (ref))
|
||||
return false;
|
||||
HOST_WIDE_INT size_in_bytes
|
||||
= tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
/* Let's see if the end of the region has been instrumented. */
|
||||
if (!has_mem_ref_been_instrumented (asan_mem_ref_get_end (ref, len),
|
||||
ref->access_size))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return size_in_bytes != -1
|
||||
&& has_mem_ref_been_instrumented (ref->start, size_in_bytes);
|
||||
}
|
||||
|
||||
/* Set REF to the memory reference present in a gimple assignment
|
||||
@ -540,7 +527,8 @@ get_mem_refs_of_builtin_call (const gimple call,
|
||||
asan_mem_ref *dst,
|
||||
tree *dst_len,
|
||||
bool *dst_is_store,
|
||||
bool *dest_is_deref)
|
||||
bool *dest_is_deref,
|
||||
bool *intercepted_p)
|
||||
{
|
||||
gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
|
||||
|
||||
@ -550,6 +538,8 @@ get_mem_refs_of_builtin_call (const gimple call,
|
||||
bool is_store = true, got_reference_p = false;
|
||||
HOST_WIDE_INT access_size = 1;
|
||||
|
||||
*intercepted_p = asan_intercepted_p ((DECL_FUNCTION_CODE (callee)));
|
||||
|
||||
switch (DECL_FUNCTION_CODE (callee))
|
||||
{
|
||||
/* (s, s, n) style memops. */
|
||||
@ -882,12 +872,12 @@ has_stmt_been_instrumented_p (gimple stmt)
|
||||
|
||||
tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
|
||||
bool src0_is_store = false, src1_is_store = false,
|
||||
dest_is_store = false, dest_is_deref = false;
|
||||
dest_is_store = false, dest_is_deref = false, intercepted_p = true;
|
||||
if (get_mem_refs_of_builtin_call (stmt,
|
||||
&src0, &src0_len, &src0_is_store,
|
||||
&src1, &src1_len, &src1_is_store,
|
||||
&dest, &dest_len, &dest_is_store,
|
||||
&dest_is_deref))
|
||||
&dest_is_deref, &intercepted_p))
|
||||
{
|
||||
if (src0.start != NULL_TREE
|
||||
&& !has_mem_ref_been_instrumented (&src0, src0_len))
|
||||
@ -918,7 +908,7 @@ update_mem_ref_hash_table (tree ref, HOST_WIDE_INT access_size)
|
||||
asan_mem_ref_init (&r, ref, access_size);
|
||||
|
||||
asan_mem_ref **slot = ht->find_slot (&r, INSERT);
|
||||
if (*slot == NULL)
|
||||
if (*slot == NULL || (*slot)->access_size < access_size)
|
||||
*slot = asan_mem_ref_new (ref, access_size);
|
||||
}
|
||||
|
||||
@ -1684,22 +1674,13 @@ static void
|
||||
build_check_stmt (location_t loc, tree base, tree len,
|
||||
HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
|
||||
bool is_non_zero_len, bool before_p, bool is_store,
|
||||
bool is_scalar_access, unsigned int align = 0,
|
||||
bool start_instrumented = false,
|
||||
bool end_instrumented = false)
|
||||
bool is_scalar_access, unsigned int align = 0)
|
||||
{
|
||||
gimple_stmt_iterator gsi = *iter;
|
||||
gimple g;
|
||||
|
||||
gcc_assert (!(size_in_bytes > 0 && !is_non_zero_len));
|
||||
|
||||
if (start_instrumented && end_instrumented)
|
||||
{
|
||||
if (!before_p)
|
||||
gsi_next (iter);
|
||||
return;
|
||||
}
|
||||
|
||||
gsi = *iter;
|
||||
|
||||
base = unshare_expr (base);
|
||||
@ -1742,10 +1723,6 @@ build_check_stmt (location_t loc, tree base, tree len,
|
||||
flags |= ASAN_CHECK_NON_ZERO_LEN;
|
||||
if (is_scalar_access)
|
||||
flags |= ASAN_CHECK_SCALAR_ACCESS;
|
||||
if (start_instrumented)
|
||||
flags |= ASAN_CHECK_START_INSTRUMENTED;
|
||||
if (end_instrumented)
|
||||
flags |= ASAN_CHECK_END_INSTRUMENTED;
|
||||
|
||||
g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
|
||||
build_int_cst (integer_type_node, flags),
|
||||
@ -1860,6 +1837,22 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
|
||||
|
||||
}
|
||||
|
||||
/* Insert a memory reference into the hash table if access length
|
||||
can be determined in compile time. */
|
||||
|
||||
static void
|
||||
maybe_update_mem_ref_hash_table (tree base, tree len)
|
||||
{
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (base))
|
||||
|| !INTEGRAL_TYPE_P (TREE_TYPE (len)))
|
||||
return;
|
||||
|
||||
HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
|
||||
|
||||
if (size_in_bytes != -1)
|
||||
update_mem_ref_hash_table (base, size_in_bytes);
|
||||
}
|
||||
|
||||
/* Instrument an access to a contiguous memory region that starts at
|
||||
the address pointed to by BASE, over a length of LEN (expressed in
|
||||
the sizeof (*BASE) bytes). ITER points to the instruction before
|
||||
@ -1878,97 +1871,20 @@ instrument_mem_region_access (tree base, tree len,
|
||||
|| integer_zerop (len))
|
||||
return;
|
||||
|
||||
/* If the beginning of the memory region has already been
|
||||
instrumented, do not instrument it. */
|
||||
bool start_instrumented = has_mem_ref_been_instrumented (base, 1);
|
||||
|
||||
/* If the end of the memory region has already been instrumented, do
|
||||
not instrument it. */
|
||||
tree end = asan_mem_ref_get_end (base, len);
|
||||
bool end_instrumented = has_mem_ref_been_instrumented (end, 1);
|
||||
|
||||
HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
|
||||
|
||||
build_check_stmt (location, base, len, size_in_bytes, iter,
|
||||
/*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
|
||||
is_store, /*is_scalar_access*/false, /*align*/0,
|
||||
start_instrumented, end_instrumented);
|
||||
|
||||
update_mem_ref_hash_table (base, 1);
|
||||
if (size_in_bytes != -1)
|
||||
update_mem_ref_hash_table (end, 1);
|
||||
if ((size_in_bytes == -1)
|
||||
|| !has_mem_ref_been_instrumented (base, size_in_bytes))
|
||||
{
|
||||
build_check_stmt (location, base, len, size_in_bytes, iter,
|
||||
/*is_non_zero_len*/size_in_bytes > 0, /*before_p*/true,
|
||||
is_store, /*is_scalar_access*/false, /*align*/0);
|
||||
}
|
||||
|
||||
maybe_update_mem_ref_hash_table (base, len);
|
||||
*iter = gsi_for_stmt (gsi_stmt (*iter));
|
||||
}
|
||||
|
||||
/* Instrument the call (to the builtin strlen function) pointed to by
|
||||
ITER.
|
||||
|
||||
This function instruments the access to the first byte of the
|
||||
argument, right before the call. After the call it instruments the
|
||||
access to the last byte of the argument; it uses the result of the
|
||||
call to deduce the offset of that last byte.
|
||||
|
||||
Upon completion, iff the call has actually been instrumented, this
|
||||
function returns TRUE and *ITER points to the statement logically
|
||||
following the built-in strlen function call *ITER was initially
|
||||
pointing to. Otherwise, the function returns FALSE and *ITER
|
||||
remains unchanged. */
|
||||
|
||||
static bool
|
||||
instrument_strlen_call (gimple_stmt_iterator *iter)
|
||||
{
|
||||
gimple g;
|
||||
gimple call = gsi_stmt (*iter);
|
||||
gcc_assert (is_gimple_call (call));
|
||||
|
||||
tree callee = gimple_call_fndecl (call);
|
||||
gcc_assert (is_builtin_fn (callee)
|
||||
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
|
||||
&& DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN);
|
||||
|
||||
location_t loc = gimple_location (call);
|
||||
|
||||
tree len = gimple_call_lhs (call);
|
||||
if (len == NULL)
|
||||
/* Some passes might clear the return value of the strlen call;
|
||||
bail out in that case. Return FALSE as we are not advancing
|
||||
*ITER. */
|
||||
return false;
|
||||
gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (len)));
|
||||
|
||||
len = maybe_cast_to_ptrmode (loc, len, iter, /*before_p*/false);
|
||||
|
||||
tree str_arg = gimple_call_arg (call, 0);
|
||||
bool start_instrumented = has_mem_ref_been_instrumented (str_arg, 1);
|
||||
|
||||
tree cptr_type = build_pointer_type (char_type_node);
|
||||
g = gimple_build_assign_with_ops (NOP_EXPR,
|
||||
make_ssa_name (cptr_type, NULL),
|
||||
str_arg, NULL);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
str_arg = gimple_assign_lhs (g);
|
||||
|
||||
build_check_stmt (loc, str_arg, NULL_TREE, 1, iter,
|
||||
/*is_non_zero_len*/true, /*before_p=*/true,
|
||||
/*is_store=*/false, /*is_scalar_access*/true, /*align*/0,
|
||||
start_instrumented, start_instrumented);
|
||||
|
||||
g = gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
|
||||
make_ssa_name (cptr_type, NULL),
|
||||
str_arg,
|
||||
len);
|
||||
gimple_set_location (g, loc);
|
||||
gsi_insert_after (iter, g, GSI_NEW_STMT);
|
||||
|
||||
build_check_stmt (loc, gimple_assign_lhs (g), NULL_TREE, 1, iter,
|
||||
/*is_non_zero_len*/true, /*before_p=*/false,
|
||||
/*is_store=*/false, /*is_scalar_access*/true, /*align*/0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Instrument the call to a built-in memory access function that is
|
||||
pointed to by the iterator ITER.
|
||||
|
||||
@ -1986,49 +1902,54 @@ instrument_builtin_call (gimple_stmt_iterator *iter)
|
||||
|
||||
gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
|
||||
|
||||
tree callee = gimple_call_fndecl (call);
|
||||
location_t loc = gimple_location (call);
|
||||
|
||||
if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN)
|
||||
iter_advanced_p = instrument_strlen_call (iter);
|
||||
else
|
||||
asan_mem_ref src0, src1, dest;
|
||||
asan_mem_ref_init (&src0, NULL, 1);
|
||||
asan_mem_ref_init (&src1, NULL, 1);
|
||||
asan_mem_ref_init (&dest, NULL, 1);
|
||||
|
||||
tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
|
||||
bool src0_is_store = false, src1_is_store = false, dest_is_store = false,
|
||||
dest_is_deref = false, intercepted_p = true;
|
||||
|
||||
if (get_mem_refs_of_builtin_call (call,
|
||||
&src0, &src0_len, &src0_is_store,
|
||||
&src1, &src1_len, &src1_is_store,
|
||||
&dest, &dest_len, &dest_is_store,
|
||||
&dest_is_deref, &intercepted_p))
|
||||
{
|
||||
asan_mem_ref src0, src1, dest;
|
||||
asan_mem_ref_init (&src0, NULL, 1);
|
||||
asan_mem_ref_init (&src1, NULL, 1);
|
||||
asan_mem_ref_init (&dest, NULL, 1);
|
||||
|
||||
tree src0_len = NULL_TREE, src1_len = NULL_TREE, dest_len = NULL_TREE;
|
||||
bool src0_is_store = false, src1_is_store = false,
|
||||
dest_is_store = false, dest_is_deref = false;
|
||||
|
||||
if (get_mem_refs_of_builtin_call (call,
|
||||
&src0, &src0_len, &src0_is_store,
|
||||
&src1, &src1_len, &src1_is_store,
|
||||
&dest, &dest_len, &dest_is_store,
|
||||
&dest_is_deref))
|
||||
if (dest_is_deref)
|
||||
{
|
||||
if (dest_is_deref)
|
||||
{
|
||||
instrument_derefs (iter, dest.start, loc, dest_is_store);
|
||||
gsi_next (iter);
|
||||
iter_advanced_p = true;
|
||||
}
|
||||
else if (src0_len || src1_len || dest_len)
|
||||
{
|
||||
if (src0.start != NULL_TREE)
|
||||
instrument_mem_region_access (src0.start, src0_len,
|
||||
iter, loc, /*is_store=*/false);
|
||||
if (src1.start != NULL_TREE)
|
||||
instrument_mem_region_access (src1.start, src1_len,
|
||||
iter, loc, /*is_store=*/false);
|
||||
if (dest.start != NULL_TREE)
|
||||
instrument_mem_region_access (dest.start, dest_len,
|
||||
iter, loc, /*is_store=*/true);
|
||||
*iter = gsi_for_stmt (call);
|
||||
gsi_next (iter);
|
||||
iter_advanced_p = true;
|
||||
}
|
||||
instrument_derefs (iter, dest.start, loc, dest_is_store);
|
||||
gsi_next (iter);
|
||||
iter_advanced_p = true;
|
||||
}
|
||||
else if (!intercepted_p
|
||||
&& (src0_len || src1_len || dest_len))
|
||||
{
|
||||
if (src0.start != NULL_TREE)
|
||||
instrument_mem_region_access (src0.start, src0_len,
|
||||
iter, loc, /*is_store=*/false);
|
||||
if (src1.start != NULL_TREE)
|
||||
instrument_mem_region_access (src1.start, src1_len,
|
||||
iter, loc, /*is_store=*/false);
|
||||
if (dest.start != NULL_TREE)
|
||||
instrument_mem_region_access (dest.start, dest_len,
|
||||
iter, loc, /*is_store=*/true);
|
||||
|
||||
*iter = gsi_for_stmt (call);
|
||||
gsi_next (iter);
|
||||
iter_advanced_p = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src0.start != NULL_TREE)
|
||||
maybe_update_mem_ref_hash_table (src0.start, src0_len);
|
||||
if (src1.start != NULL_TREE)
|
||||
maybe_update_mem_ref_hash_table (src1.start, src1_len);
|
||||
if (dest.start != NULL_TREE)
|
||||
maybe_update_mem_ref_hash_table (dest.start, dest_len);
|
||||
}
|
||||
}
|
||||
return iter_advanced_p;
|
||||
@ -2586,8 +2507,6 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
|
||||
bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
|
||||
bool is_store = (flags & ASAN_CHECK_STORE) != 0;
|
||||
bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
|
||||
bool start_instrumented = (flags & ASAN_CHECK_START_INSTRUMENTED) != 0;
|
||||
bool end_instrumented = (flags & ASAN_CHECK_END_INSTRUMENTED) != 0;
|
||||
|
||||
tree base = gimple_call_arg (g, 1);
|
||||
tree len = gimple_call_arg (g, 2);
|
||||
@ -2692,46 +2611,42 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
|
||||
else
|
||||
{
|
||||
/* Slow path for 1, 2 and 4 byte accesses. */
|
||||
|
||||
if (!start_instrumented)
|
||||
/* Test (shadow != 0)
|
||||
& ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
|
||||
tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
|
||||
shadow_ptr_type);
|
||||
gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
|
||||
gimple_seq seq = NULL;
|
||||
gimple_seq_add_stmt (&seq, shadow_test);
|
||||
/* Aligned (>= 8 bytes) can test just
|
||||
(real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
|
||||
to be 0. */
|
||||
if (align < 8)
|
||||
{
|
||||
/* Test (shadow != 0)
|
||||
& ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
|
||||
tree shadow = build_shadow_mem_access (&gsi, loc, base_addr,
|
||||
shadow_ptr_type);
|
||||
gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
|
||||
gimple_seq seq = NULL;
|
||||
gimple_seq_add_stmt (&seq, shadow_test);
|
||||
/* Aligned (>= 8 bytes) can test just
|
||||
(real_size_in_bytes - 1 >= shadow), as base_addr & 7 is known
|
||||
to be 0. */
|
||||
if (align < 8)
|
||||
{
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
|
||||
base_addr, 7));
|
||||
gimple_seq_add_stmt (&seq,
|
||||
build_type_cast (shadow_type,
|
||||
gimple_seq_last (seq)));
|
||||
if (real_size_in_bytes > 1)
|
||||
gimple_seq_add_stmt (&seq,
|
||||
build_assign (PLUS_EXPR,
|
||||
gimple_seq_last (seq),
|
||||
real_size_in_bytes - 1));
|
||||
t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
|
||||
}
|
||||
else
|
||||
t = build_int_cst (shadow_type, real_size_in_bytes - 1);
|
||||
gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
|
||||
gimple_seq_last (seq)));
|
||||
t = gimple_assign_lhs (gimple_seq_last (seq));
|
||||
gimple_seq_set_location (seq, loc);
|
||||
gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
|
||||
base_addr, 7));
|
||||
gimple_seq_add_stmt (&seq,
|
||||
build_type_cast (shadow_type,
|
||||
gimple_seq_last (seq)));
|
||||
if (real_size_in_bytes > 1)
|
||||
gimple_seq_add_stmt (&seq,
|
||||
build_assign (PLUS_EXPR,
|
||||
gimple_seq_last (seq),
|
||||
real_size_in_bytes - 1));
|
||||
t = gimple_assign_lhs (gimple_seq_last_stmt (seq));
|
||||
}
|
||||
else
|
||||
t = build_int_cst (shadow_type, real_size_in_bytes - 1);
|
||||
gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, t, shadow));
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
|
||||
gimple_seq_last (seq)));
|
||||
t = gimple_assign_lhs (gimple_seq_last (seq));
|
||||
gimple_seq_set_location (seq, loc);
|
||||
gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
|
||||
|
||||
/* For non-constant, misaligned or otherwise weird access sizes,
|
||||
check first and last byte. */
|
||||
if (size_in_bytes == -1 && !end_instrumented)
|
||||
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, NULL),
|
||||
@ -2762,9 +2677,8 @@ asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls)
|
||||
shadow));
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
|
||||
gimple_seq_last (seq)));
|
||||
if (!start_instrumented)
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
|
||||
gimple_seq_last (seq)));
|
||||
gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t,
|
||||
gimple_seq_last (seq)));
|
||||
t = gimple_assign_lhs (gimple_seq_last (seq));
|
||||
gimple_seq_set_location (seq, loc);
|
||||
gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
|
||||
|
24
gcc/asan.h
24
gcc/asan.h
@ -78,4 +78,28 @@ asan_red_zone_size (unsigned int size)
|
||||
|
||||
extern bool set_asan_shadow_offset (const char *);
|
||||
|
||||
/* Return TRUE if builtin with given FCODE will be intercepted by
|
||||
libasan. */
|
||||
|
||||
static inline bool
|
||||
asan_intercepted_p (enum built_in_function fcode)
|
||||
{
|
||||
return fcode == BUILT_IN_INDEX
|
||||
|| fcode == BUILT_IN_MEMCHR
|
||||
|| fcode == BUILT_IN_MEMCMP
|
||||
|| fcode == BUILT_IN_MEMCPY
|
||||
|| fcode == BUILT_IN_MEMMOVE
|
||||
|| fcode == BUILT_IN_MEMSET
|
||||
|| fcode == BUILT_IN_STRCASECMP
|
||||
|| fcode == BUILT_IN_STRCAT
|
||||
|| fcode == BUILT_IN_STRCHR
|
||||
|| fcode == BUILT_IN_STRCMP
|
||||
|| fcode == BUILT_IN_STRCPY
|
||||
|| fcode == BUILT_IN_STRDUP
|
||||
|| fcode == BUILT_IN_STRLEN
|
||||
|| fcode == BUILT_IN_STRNCASECMP
|
||||
|| fcode == BUILT_IN_STRNCAT
|
||||
|| fcode == BUILT_IN_STRNCMP
|
||||
|| fcode == BUILT_IN_STRNCPY;
|
||||
}
|
||||
#endif /* TREE_ASAN */
|
||||
|
@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "value-prof.h"
|
||||
#include "diagnostic-core.h"
|
||||
#include "builtins.h"
|
||||
#include "asan.h"
|
||||
#include "ubsan.h"
|
||||
#include "cilk.h"
|
||||
|
||||
@ -5765,6 +5766,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
|
||||
enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
|
||||
int flags;
|
||||
|
||||
/* When ASan is enabled, we don't want to expand some memory/string
|
||||
builtins and rely on libsanitizer's hooks. This allows us to avoid
|
||||
redundant checks and be sure, that possible overflow will be detected
|
||||
by ASan. */
|
||||
|
||||
if ((flag_sanitize & SANITIZE_ADDRESS) && asan_intercepted_p (fcode))
|
||||
return expand_call (exp, target, ignore);
|
||||
|
||||
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
|
||||
return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
|
||||
|
||||
|
@ -1,3 +1,21 @@
|
||||
2014-10-28 Max Ostapenko <m.ostapenko@partner.samsung.com>
|
||||
|
||||
* c-c++-common/asan/no-redundant-instrumentation-1.c: Updated test.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-4.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-5.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-6.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-7.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-8.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-2.c: Removed.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-9.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-10.c: New test.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-11.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-12.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-13.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-14.c: Likewise.
|
||||
* c-c++-common/asan/no-redundant-instrumentation-15.c: Likewise.
|
||||
* c-c++-common/asan/pr63638.c: Likewise.
|
||||
|
||||
2014-10-28 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR middle-end/63665
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
|
||||
|
||||
extern char tab[4];
|
||||
extern char tab[6];
|
||||
|
||||
static int
|
||||
test0 ()
|
||||
@ -35,17 +35,10 @@ test1 (int i)
|
||||
the initialization. */
|
||||
foo[i] = 1;
|
||||
|
||||
/*__builtin___asan_report_store_n called once here to instrument
|
||||
the store to the memory region of tab. */
|
||||
/* Instrument tab memory region. */
|
||||
__builtin_memset (tab, 3, sizeof (tab));
|
||||
|
||||
/* There is no instrumentation for the two memset calls below. */
|
||||
__builtin_memset (tab, 4, sizeof (tab));
|
||||
__builtin_memset (tab, 5, sizeof (tab));
|
||||
|
||||
/* There is a call to __builtin___asan_report_store_n and a call
|
||||
to __builtin___asan_report_load_n to instrument the store to
|
||||
(subset of) the memory region of tab. */
|
||||
/* Instrument tab[1] with access size 3. */
|
||||
__builtin_memcpy (&tab[1], foo + i, 3);
|
||||
|
||||
/* This should not generate a __builtin___asan_report_load1 because
|
||||
@ -63,6 +56,5 @@ main ()
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 3 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-not "__builtin___asan_report_load1" "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -5,13 +5,13 @@
|
||||
void
|
||||
foo (int *a, char *b, char *c)
|
||||
{
|
||||
/* One check for c[0], one check for a[], one check for c, two checks for b. */
|
||||
/* One check for c[0], one check for a[]. */
|
||||
__builtin_memmove (c, b, a[c[0]]);
|
||||
/* For a total of 5 checks. */
|
||||
/* For a total of 2 checks. */
|
||||
int d = c[0] == 1;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 5 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -5,14 +5,12 @@
|
||||
void
|
||||
foo (int *a, char *b, char *c)
|
||||
{
|
||||
/* One check for b[0], one check for a[], 2 checks for c and one checks for b. */
|
||||
__builtin_memmove (c, b, a[b[0]]);
|
||||
/* For a total of 5 checks. */
|
||||
/* One check for a[]. */
|
||||
__builtin_memmove (c, b, a[0]);
|
||||
/* For a total of 1 checks. */
|
||||
int d = a[0] == 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 5 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -5,16 +5,15 @@
|
||||
void
|
||||
foo (int *a, char *b, char *c)
|
||||
{
|
||||
/* One check for c[0], one check for a[], one check for c and 2 checks for b. */
|
||||
/* One check for c[0], one check for a[]. */
|
||||
__builtin_memmove (c, b, a[c[0]]);
|
||||
/* One check for a[], one check for c and one check for b. */
|
||||
/* One check for b[0], one check for a[]. */
|
||||
__builtin_memmove (c, b, a[b[0]]);
|
||||
/* For a total of 8 checks. */
|
||||
/* For a total of 4 checks. */
|
||||
int d = c[0] == b[0];
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 8 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 4 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -2,26 +2,22 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
|
||||
|
||||
char e[200];
|
||||
char e[5];
|
||||
|
||||
struct S
|
||||
extern struct S
|
||||
{
|
||||
char a[100];
|
||||
char b[100];
|
||||
int a;
|
||||
char b;
|
||||
} s;
|
||||
|
||||
int
|
||||
foo (int *a, char *b, char *c)
|
||||
{
|
||||
/* 2 checks for s.a, 2 checks for e. */
|
||||
int d = __builtin_memcmp (s.a, e, 100);
|
||||
/* One check for s.a and one check for e. */
|
||||
d += __builtin_memcmp (s.a, e, 200);
|
||||
/* For a total of 6 checks. */
|
||||
return d;
|
||||
int d = __builtin_memcmp (&s.a, e, 4);
|
||||
/* No check because s.a was instrumented above with access size 4. */
|
||||
return s.a;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 6 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 4 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-not "__builtin___asan_report_store" "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-not "& 7" "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-not "__builtin___asan_report_load4" "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -5,16 +5,16 @@
|
||||
char
|
||||
foo (int *a, char *b, char *c)
|
||||
{
|
||||
/* One check for b[0], one check for a[], two checks for c and one check for b. */
|
||||
/* One check for b[0], one check for a[]. */
|
||||
__builtin_memmove (c, b, a[b[0]]);
|
||||
/* One check for c[0], one check for a[]. */
|
||||
__builtin_memmove (b, c, a[c[0]]);
|
||||
/* No checks here. */
|
||||
return c[0] + b[0];
|
||||
/* For a total of 5 checks. */
|
||||
/* For a total of 4 checks. */
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 5 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "& 7" 4 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 2 "sanopt" } } */
|
||||
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 2 "sanopt" } } */
|
||||
/* { dg-final { cleanup-tree-dump "sanopt" } } */
|
||||
|
@ -9,14 +9,8 @@ char a[2] = "0";
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
__attribute__((no_sanitize_address, noinline)) __SIZE_TYPE__
|
||||
strlen (const char *p) {
|
||||
|
||||
__SIZE_TYPE__ n = 0;
|
||||
for (; *p; ++n, ++p);
|
||||
return n;
|
||||
}
|
||||
__SIZE_TYPE__
|
||||
strlen (const char *p);
|
||||
|
||||
int main () {
|
||||
char *p = &a[0];
|
||||
@ -25,6 +19,6 @@ int main () {
|
||||
return __builtin_strlen (a);
|
||||
}
|
||||
|
||||
/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strlen-overflow-1.c:25|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 1 bytes inside of global variable" } */
|
||||
/* { dg-output "READ of size 2 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strlen-overflow-1.c:19|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*0x\[0-9a-f\]+ is located 0 bytes to the right of global variable" } */
|
||||
|
Loading…
x
Reference in New Issue
Block a user