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:
Max Ostapenko 2014-10-28 14:36:54 +02:00 committed by Maxim Ostapenko
parent 9ccaac1188
commit bdea98ca2e
12 changed files with 235 additions and 267 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } */