Commit 8946c29e by Yury Gribov Committed by Yury Gribov

New asan-instrumentation-with-call-threshold parameter.

2014-06-16  Yury Gribov  <y.gribov@samsung.com>

	New asan-instrumentation-with-call-threshold parameter.

	gcc/
	* asan.c (check_func): New function.
	(maybe_create_ssa_name): Likewise.
	(build_check_stmt_with_calls): Likewise.
	(use_calls_p): Likewise.
	(report_error_func): Change interface.
	(build_check_stmt): Allow non-integer lengths; add support
	for new parameter.
	(asan_instrument): Likewise.
	(instrument_mem_region_access): Moved code to
	build_check_stmt.
	(instrument_derefs): Likewise.
	(instrument_strlen_call): Likewise.
	* cfgcleanup.c (old_insns_match_p): Add support for new
	functions.
	* doc/invoke.texi: Describe new parameter.
	* params.def: Define new parameter.
	* params.h: Likewise.
	* sanitizer.def: Describe new builtins.

	gcc/testsuite/
	* c-c++-common/asan/instrument-with-calls-1.c: New test.
	* c-c++-common/asan/instrument-with-calls-2.c: Likewise.
	* c-c++-common/asan/instrument-with-calls-3.c: Likewise.
	* c-c++-common/asan/no-redundant-instrumentation-1.c: Update
	test patterns.
	* c-c++-common/asan/no-redundant-instrumentation-2.c:
	Likewise.
	* 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.

From-SVN: r211699
parent 5d5cb4d4
2014-06-16 Yury Gribov <y.gribov@samsung.com>
* asan.c (check_func): New function.
(maybe_create_ssa_name): Likewise.
(build_check_stmt_with_calls): Likewise.
(use_calls_p): Likewise.
(report_error_func): Change interface.
(build_check_stmt): Allow non-integer lengths; add support
for new parameter.
(asan_instrument): Likewise.
(instrument_mem_region_access): Moved code to
build_check_stmt.
(instrument_derefs): Likewise.
(instrument_strlen_call): Likewise.
* cfgcleanup.c (old_insns_match_p): Add support for new
functions.
* doc/invoke.texi: Describe new parameter.
* params.def: Define new parameter.
* params.h: Likewise.
* sanitizer.def: Describe new builtins.
2014-06-16 Richard Biener <rguenther@suse.de> 2014-06-16 Richard Biener <rguenther@suse.de>
* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children):
......
...@@ -243,6 +243,19 @@ static GTY(()) tree shadow_ptr_types[2]; ...@@ -243,6 +243,19 @@ static GTY(()) tree shadow_ptr_types[2];
/* Decl for __asan_option_detect_stack_use_after_return. */ /* Decl for __asan_option_detect_stack_use_after_return. */
static GTY(()) tree asan_detect_stack_use_after_return; static GTY(()) tree asan_detect_stack_use_after_return;
/* Number of instrumentations in current function so far. */
static int asan_num_accesses;
/* Check whether we should replace inline instrumentation with calls. */
static inline bool
use_calls_p ()
{
return ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
&& asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
}
/* Hashtable support for memory references used by gimple /* Hashtable support for memory references used by gimple
statements. */ statements. */
...@@ -1320,7 +1333,7 @@ asan_protect_global (tree decl) ...@@ -1320,7 +1333,7 @@ asan_protect_global (tree decl)
IS_STORE is either 1 (for a store) or 0 (for a load). */ IS_STORE is either 1 (for a store) or 0 (for a load). */
static tree static tree
report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, bool slow_p) report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, int *nargs)
{ {
static enum built_in_function report[2][6] static enum built_in_function report[2][6]
= { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2, = { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2,
...@@ -1329,13 +1342,37 @@ report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, bool slow_p) ...@@ -1329,13 +1342,37 @@ report_error_func (bool is_store, HOST_WIDE_INT size_in_bytes, bool slow_p)
{ BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2, { BUILT_IN_ASAN_REPORT_STORE1, BUILT_IN_ASAN_REPORT_STORE2,
BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8, BUILT_IN_ASAN_REPORT_STORE4, BUILT_IN_ASAN_REPORT_STORE8,
BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } }; BUILT_IN_ASAN_REPORT_STORE16, BUILT_IN_ASAN_REPORT_STORE_N } };
if ((size_in_bytes & (size_in_bytes - 1)) != 0 if (size_in_bytes == -1)
|| size_in_bytes > 16 {
|| slow_p) *nargs = 2;
return builtin_decl_implicit (report[is_store][5]); return builtin_decl_implicit (report[is_store][5]);
}
*nargs = 1;
return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]); return builtin_decl_implicit (report[is_store][exact_log2 (size_in_bytes)]);
} }
/* Construct a function tree for __asan_{load,store}{1,2,4,8,16,_n}.
IS_STORE is either 1 (for a store) or 0 (for a load). */
static tree
check_func (bool is_store, int size_in_bytes, int *nargs)
{
static enum built_in_function check[2][6]
= { { BUILT_IN_ASAN_LOAD1, BUILT_IN_ASAN_LOAD2,
BUILT_IN_ASAN_LOAD4, BUILT_IN_ASAN_LOAD8,
BUILT_IN_ASAN_LOAD16, BUILT_IN_ASAN_LOADN },
{ BUILT_IN_ASAN_STORE1, BUILT_IN_ASAN_STORE2,
BUILT_IN_ASAN_STORE4, BUILT_IN_ASAN_STORE8,
BUILT_IN_ASAN_STORE16, BUILT_IN_ASAN_STOREN } };
if (size_in_bytes == -1)
{
*nargs = 2;
return builtin_decl_implicit (check[is_store][5]);
}
*nargs = 1;
return builtin_decl_implicit (check[is_store][exact_log2 (size_in_bytes)]);
}
/* Split the current basic block and create a condition statement /* Split the current basic block and create a condition statement
insertion point right before or after the statement pointed to by insertion point right before or after the statement pointed to by
ITER. Return an iterator to the point at which the caller might ITER. Return an iterator to the point at which the caller might
...@@ -1495,6 +1532,76 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, ...@@ -1495,6 +1532,76 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
return gimple_assign_lhs (g); return gimple_assign_lhs (g);
} }
/* BASE can already be an SSA_NAME; in that case, do not create a
new SSA_NAME for it. */
static tree
maybe_create_ssa_name (location_t loc, tree base, gimple_stmt_iterator *iter,
bool before_p)
{
if (TREE_CODE (base) == SSA_NAME)
return base;
gimple g
= gimple_build_assign_with_ops (TREE_CODE (base),
make_ssa_name (TREE_TYPE (base), NULL),
base, NULL_TREE);
gimple_set_location (g, loc);
if (before_p)
gsi_insert_before (iter, g, GSI_SAME_STMT);
else
gsi_insert_after (iter, g, GSI_NEW_STMT);
return gimple_assign_lhs (g);
}
/* Instrument the memory access instruction using callbacks.
Parameters are similar to BUILD_CHECK_STMT. */
static void
build_check_stmt_with_calls (location_t loc, tree base, tree len,
HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
bool before_p, bool is_store, bool is_scalar_access)
{
gimple_stmt_iterator gsi = *iter;
tree base_ssa = maybe_create_ssa_name (loc, base, &gsi, before_p);
gimple g
= gimple_build_assign_with_ops (NOP_EXPR,
make_ssa_name (pointer_sized_int_node, NULL),
base_ssa, NULL_TREE);
gimple_set_location (g, loc);
if (before_p)
gsi_insert_before (&gsi, g, GSI_NEW_STMT);
else
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
tree base_addr = gimple_assign_lhs (g);
int nargs;
tree fun
= check_func (is_store, is_scalar_access ? size_in_bytes : -1, &nargs);
if (nargs == 1)
g = gimple_build_call (fun, 1, base_addr);
else
{
gcc_assert (nargs == 2);
g = gimple_build_assign_with_ops (NOP_EXPR,
make_ssa_name (pointer_sized_int_node,
NULL),
len, NULL_TREE);
gimple_set_location (g, loc);
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
tree sz_arg = gimple_assign_lhs (g);
g = gimple_build_call (fun, nargs, base_addr, sz_arg);
}
gimple_set_location (g, loc);
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
if (!before_p)
{
gsi_next (&gsi);
*iter = gsi;
}
}
/* Instrument the memory access instruction BASE. Insert new /* Instrument the memory access instruction BASE. Insert new
statements before or after ITER. statements before or after ITER.
...@@ -1502,111 +1609,192 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, ...@@ -1502,111 +1609,192 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
SSA_NAME, or a non-SSA expression. LOCATION is the source code SSA_NAME, or a non-SSA expression. LOCATION is the source code
location. IS_STORE is TRUE for a store, FALSE for a load. location. IS_STORE is TRUE for a store, FALSE for a load.
BEFORE_P is TRUE for inserting the instrumentation code before BEFORE_P is TRUE for inserting the instrumentation code before
ITER, FALSE for inserting it after ITER. ITER, FALSE for inserting it after ITER. IS_SCALAR_ACCESS is TRUE
for a scalar memory access and FALSE for memory region access.
NON_ZERO_P is TRUE if memory region is guaranteed to have non-zero
length. ALIGN tells alignment of accessed memory object.
START_INSTRUMENTED and END_INSTRUMENTED are TRUE if start/end of
memory region have already been instrumented.
If BEFORE_P is TRUE, *ITER is arranged to still point to the If BEFORE_P is TRUE, *ITER is arranged to still point to the
statement it was pointing to prior to calling this function, statement it was pointing to prior to calling this function,
otherwise, it points to the statement logically following it. */ otherwise, it points to the statement logically following it. */
static void static void
build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter, build_check_stmt (location_t location, tree base, tree len,
bool before_p, bool is_store, HOST_WIDE_INT size_in_bytes, HOST_WIDE_INT size_in_bytes, gimple_stmt_iterator *iter,
bool slow_p = false) bool non_zero_len_p, bool before_p, bool is_store,
bool is_scalar_access, unsigned int align = 0,
bool start_instrumented = false,
bool end_instrumented = false)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi = *iter;
basic_block then_bb, else_bb;
tree t, base_addr, shadow;
gimple g; gimple g;
tree shadow_ptr_type = shadow_ptr_types[size_in_bytes == 16 ? 1 : 0];
tree shadow_type = TREE_TYPE (shadow_ptr_type);
tree uintptr_type tree uintptr_type
= build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (base)), 1); = build_nonstandard_integer_type (TYPE_PRECISION (TREE_TYPE (base)), 1);
tree base_ssa = base;
HOST_WIDE_INT real_size_in_bytes = size_in_bytes; gcc_assert (!(size_in_bytes > 0 && !non_zero_len_p));
tree sz_arg = NULL_TREE;
if (len)
if (size_in_bytes == 1) len = unshare_expr (len);
slow_p = false; else
else if ((size_in_bytes & (size_in_bytes - 1)) != 0 {
|| size_in_bytes > 16 gcc_assert (size_in_bytes != -1);
|| slow_p) len = build_int_cst (pointer_sized_int_node, size_in_bytes);
}
if (size_in_bytes > 1)
{ {
real_size_in_bytes = 1; if ((size_in_bytes & (size_in_bytes - 1)) != 0
slow_p = true; || size_in_bytes > 16)
size_in_bytes = -1;
else if (align && align < size_in_bytes * BITS_PER_UNIT)
{
/* On non-strict alignment targets, if
16-byte access is just 8-byte aligned,
this will result in misaligned shadow
memory 2 byte load, but otherwise can
be handled using one read. */
if (size_in_bytes != 16
|| STRICT_ALIGNMENT
|| align < 8 * BITS_PER_UNIT)
size_in_bytes = -1;
}
}
HOST_WIDE_INT real_size_in_bytes = size_in_bytes == -1 ? 1 : size_in_bytes;
tree shadow_ptr_type = shadow_ptr_types[real_size_in_bytes == 16 ? 1 : 0];
tree shadow_type = TREE_TYPE (shadow_ptr_type);
base = unshare_expr (base);
if (use_calls_p ())
{
gsi = *iter;
build_check_stmt_with_calls (location, base, len, size_in_bytes, iter,
before_p, is_store, is_scalar_access);
return;
}
++asan_num_accesses;
if (!non_zero_len_p)
{
gcc_assert (before_p);
/* So, the length of the memory area to asan-protect is
non-constant. Let's guard the generated instrumentation code
like:
if (len != 0)
{
//asan instrumentation code goes here.
}
// falltrough instructions, starting with *ITER. */
g = gimple_build_cond (NE_EXPR,
len,
build_int_cst (TREE_TYPE (len), 0),
NULL_TREE, NULL_TREE);
gimple_set_location (g, location);
basic_block then_bb, fallthrough_bb;
insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true,
&then_bb, &fallthrough_bb);
/* Note that fallthrough_bb starts with the statement that was
pointed to by ITER. */
/* The 'then block' of the 'if (len != 0) condition is where
we'll generate the asan instrumentation code now. */
gsi = gsi_last_bb (then_bb);
build_check_stmt (location, base, len, size_in_bytes, &gsi,
/*non_zero_len_p*/true, /*before_p*/true, is_store,
is_scalar_access, align,
start_instrumented, end_instrumented);
return;
} }
/* Get an iterator on the point where we can add the condition /* Get an iterator on the point where we can add the condition
statement for the instrumentation. */ statement for the instrumentation. */
gsi = create_cond_insert_point (iter, before_p, basic_block then_bb, else_bb;
gsi = create_cond_insert_point (&gsi, before_p,
/*then_more_likely_p=*/false, /*then_more_likely_p=*/false,
/*create_then_fallthru_edge=*/false, /*create_then_fallthru_edge=*/false,
&then_bb, &then_bb,
&else_bb); &else_bb);
base = unshare_expr (base); tree base_ssa = maybe_create_ssa_name (location, base, &gsi,
/*before_p*/false);
/* BASE can already be an SSA_NAME; in that case, do not create a
new SSA_NAME for it. */
if (TREE_CODE (base) != SSA_NAME)
{
g = gimple_build_assign_with_ops (TREE_CODE (base),
make_ssa_name (TREE_TYPE (base), NULL),
base, NULL_TREE);
gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
base_ssa = gimple_assign_lhs (g);
}
g = gimple_build_assign_with_ops (NOP_EXPR, g = gimple_build_assign_with_ops (NOP_EXPR,
make_ssa_name (uintptr_type, NULL), make_ssa_name (uintptr_type, NULL),
base_ssa, NULL_TREE); base_ssa, NULL_TREE);
gimple_set_location (g, location); gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT); gsi_insert_after (&gsi, g, GSI_NEW_STMT);
base_addr = gimple_assign_lhs (g); tree base_addr = gimple_assign_lhs (g);
/* Build
(base_addr >> ASAN_SHADOW_SHIFT) + targetm.asan_shadow_offset (). */
shadow = build_shadow_mem_access (&gsi, location, base_addr,
shadow_ptr_type);
if (real_size_in_bytes < 8) tree t;
if (real_size_in_bytes >= 8)
{
tree shadow = build_shadow_mem_access (&gsi, location, base_addr,
shadow_ptr_type);
t = shadow;
}
else
{ {
/* Slow path for 1, 2 and 4 byte accesses. /* Slow path for 1, 2 and 4 byte accesses. */
Test (shadow != 0)
& ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */ if (!start_instrumented)
gimple_seq seq = NULL;
gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
gimple_seq_add_stmt (&seq, shadow_test);
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));
gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, gimple_seq_last (seq),
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, location);
gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
/* For weird access sizes or misaligned, check first and last byte. */
if (slow_p)
{ {
/* Test (shadow != 0)
& ((base_addr & 7) + (real_size_in_bytes - 1)) >= shadow). */
tree shadow = build_shadow_mem_access (&gsi, location, 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);
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));
gimple_seq_add_stmt (&seq, build_assign (GE_EXPR,
gimple_seq_last (seq),
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, location);
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)
{
g = gimple_build_assign_with_ops (MINUS_EXPR,
make_ssa_name (uintptr_type, NULL),
len,
build_int_cst (uintptr_type, 1));
gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
tree last = gimple_assign_lhs (g);
g = gimple_build_assign_with_ops (PLUS_EXPR, g = gimple_build_assign_with_ops (PLUS_EXPR,
make_ssa_name (uintptr_type, NULL), make_ssa_name (uintptr_type, NULL),
base_addr, base_addr,
build_int_cst (uintptr_type, last);
size_in_bytes - 1));
gimple_set_location (g, location); gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT); gsi_insert_after (&gsi, g, GSI_NEW_STMT);
tree base_end_addr = gimple_assign_lhs (g); tree base_end_addr = gimple_assign_lhs (g);
shadow = build_shadow_mem_access (&gsi, location, base_end_addr, tree shadow = build_shadow_mem_access (&gsi, location, base_end_addr,
shadow_ptr_type); shadow_ptr_type);
seq = NULL; gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
shadow_test = build_assign (NE_EXPR, shadow, 0); gimple_seq seq = NULL;
gimple_seq_add_stmt (&seq, shadow_test); gimple_seq_add_stmt (&seq, shadow_test);
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR,
base_end_addr, 7)); base_end_addr, 7));
...@@ -1617,16 +1805,14 @@ build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter, ...@@ -1617,16 +1805,14 @@ build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
shadow)); shadow));
gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test, gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
gimple_seq_last (seq))); gimple_seq_last (seq)));
gimple_seq_add_stmt (&seq, build_assign (BIT_IOR_EXPR, t, if (!start_instrumented)
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)); t = gimple_assign_lhs (gimple_seq_last (seq));
gimple_seq_set_location (seq, location); gimple_seq_set_location (seq, location);
gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING); gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
sz_arg = build_int_cst (pointer_sized_int_node, size_in_bytes);
} }
} }
else
t = shadow;
g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0), g = gimple_build_cond (NE_EXPR, t, build_int_cst (TREE_TYPE (t), 0),
NULL_TREE, NULL_TREE); NULL_TREE, NULL_TREE);
...@@ -1635,8 +1821,23 @@ build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter, ...@@ -1635,8 +1821,23 @@ build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
/* Generate call to the run-time library (e.g. __asan_report_load8). */ /* Generate call to the run-time library (e.g. __asan_report_load8). */
gsi = gsi_start_bb (then_bb); gsi = gsi_start_bb (then_bb);
g = gimple_build_call (report_error_func (is_store, size_in_bytes, slow_p), int nargs;
sz_arg ? 2 : 1, base_addr, sz_arg); tree fun = report_error_func (is_store, is_scalar_access ? size_in_bytes : -1,
&nargs);
if (nargs == 1)
g = gimple_build_call (fun, 1, base_addr);
else
{
gcc_assert (nargs == 2);
g = gimple_build_assign_with_ops (NOP_EXPR,
make_ssa_name (pointer_sized_int_node,
NULL),
len, NULL_TREE);
gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT);
tree sz_arg = gimple_assign_lhs (g);
g = gimple_build_call (fun, nargs, base_addr, sz_arg);
}
gimple_set_location (g, location); gimple_set_location (g, location);
gsi_insert_after (&gsi, g, GSI_NEW_STMT); gsi_insert_after (&gsi, g, GSI_NEW_STMT);
...@@ -1731,31 +1932,10 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, ...@@ -1731,31 +1932,10 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
base = build_fold_addr_expr (t); base = build_fold_addr_expr (t);
if (!has_mem_ref_been_instrumented (base, size_in_bytes)) if (!has_mem_ref_been_instrumented (base, size_in_bytes))
{ {
bool slow_p = false; unsigned int align = get_object_alignment (t);
if (size_in_bytes > 1) build_check_stmt (location, base, NULL_TREE, size_in_bytes, iter,
{ /*non_zero_len_p*/size_in_bytes > 0, /*before_p=*/true,
if ((size_in_bytes & (size_in_bytes - 1)) != 0 is_store, /*is_scalar_access*/true, align);
|| size_in_bytes > 16)
slow_p = true;
else
{
unsigned int align = get_object_alignment (t);
if (align < size_in_bytes * BITS_PER_UNIT)
{
/* On non-strict alignment targets, if
16-byte access is just 8-byte aligned,
this will result in misaligned shadow
memory 2 byte load, but otherwise can
be handled using one read. */
if (size_in_bytes != 16
|| STRICT_ALIGNMENT
|| align < 8 * BITS_PER_UNIT)
slow_p = true;
}
}
}
build_check_stmt (location, base, iter, /*before_p=*/true,
is_store, size_in_bytes, slow_p);
update_mem_ref_hash_table (base, size_in_bytes); update_mem_ref_hash_table (base, size_in_bytes);
update_mem_ref_hash_table (t, size_in_bytes); update_mem_ref_hash_table (t, size_in_bytes);
} }
...@@ -1780,142 +1960,24 @@ instrument_mem_region_access (tree base, tree len, ...@@ -1780,142 +1960,24 @@ instrument_mem_region_access (tree base, tree len,
|| integer_zerop (len)) || integer_zerop (len))
return; return;
gimple_stmt_iterator gsi = *iter;
basic_block fallthrough_bb = NULL, then_bb = NULL;
/* If the beginning of the memory region has already been /* If the beginning of the memory region has already been
instrumented, do not instrument it. */ instrumented, do not instrument it. */
bool start_instrumented = has_mem_ref_been_instrumented (base, 1); bool start_instrumented = has_mem_ref_been_instrumented (base, 1);
/* If the end of the memory region has already been instrumented, do /* If the end of the memory region has already been instrumented, do
not instrument it. */ not instrument it. */
tree end = asan_mem_ref_get_end (base, len); tree end = asan_mem_ref_get_end (base, len);
bool end_instrumented = has_mem_ref_been_instrumented (end, 1); bool end_instrumented = has_mem_ref_been_instrumented (end, 1);
if (start_instrumented && end_instrumented) HOST_WIDE_INT size_in_bytes = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
return;
if (!is_gimple_constant (len))
{
/* So, the length of the memory area to asan-protect is
non-constant. Let's guard the generated instrumentation code
like:
if (len != 0)
{
//asan instrumentation code goes here.
}
// falltrough instructions, starting with *ITER. */
gimple g = gimple_build_cond (NE_EXPR,
len,
build_int_cst (TREE_TYPE (len), 0),
NULL_TREE, NULL_TREE);
gimple_set_location (g, location);
insert_if_then_before_iter (g, iter, /*then_more_likely_p=*/true,
&then_bb, &fallthrough_bb);
/* Note that fallthrough_bb starts with the statement that was
pointed to by ITER. */
/* The 'then block' of the 'if (len != 0) condition is where
we'll generate the asan instrumentation code now. */
gsi = gsi_last_bb (then_bb);
}
if (!start_instrumented)
{
/* Instrument the beginning of the memory region to be accessed,
and arrange for the rest of the intrumentation code to be
inserted in the then block *after* the current gsi. */
build_check_stmt (location, base, &gsi, /*before_p=*/true, is_store, 1);
if (then_bb)
/* We are in the case where the length of the region is not
constant; so instrumentation code is being generated in the
'then block' of the 'if (len != 0) condition. Let's arrange
for the subsequent instrumentation statements to go in the
'then block'. */
gsi = gsi_last_bb (then_bb);
else
{
*iter = gsi;
/* Don't remember this access as instrumented, if length
is unknown. It might be zero and not being actually
instrumented, so we can't rely on it being instrumented. */
update_mem_ref_hash_table (base, 1);
}
}
if (end_instrumented)
return;
/* We want to instrument the access at the end of the memory region, build_check_stmt (location, base, len, size_in_bytes, iter,
which is at (base + len - 1). */ /*non_zero_len_p*/size_in_bytes > 0, /*before_p*/true,
is_store, /*is_scalar_access*/false, /*align*/0,
start_instrumented, end_instrumented);
/* offset = len - 1; */ update_mem_ref_hash_table (base, 1);
len = unshare_expr (len); if (size_in_bytes != -1)
tree offset;
gimple_seq seq = NULL;
if (TREE_CODE (len) == INTEGER_CST)
offset = fold_build2 (MINUS_EXPR, size_type_node,
fold_convert (size_type_node, len),
build_int_cst (size_type_node, 1));
else
{
gimple g;
tree t;
if (TREE_CODE (len) != SSA_NAME)
{
t = make_ssa_name (TREE_TYPE (len), NULL);
g = gimple_build_assign_with_ops (TREE_CODE (len), t, len, NULL);
gimple_set_location (g, location);
gimple_seq_add_stmt_without_update (&seq, g);
len = t;
}
if (!useless_type_conversion_p (size_type_node, TREE_TYPE (len)))
{
t = make_ssa_name (size_type_node, NULL);
g = gimple_build_assign_with_ops (NOP_EXPR, t, len, NULL);
gimple_set_location (g, location);
gimple_seq_add_stmt_without_update (&seq, g);
len = t;
}
t = make_ssa_name (size_type_node, NULL);
g = gimple_build_assign_with_ops (MINUS_EXPR, t, len,
build_int_cst (size_type_node, 1));
gimple_set_location (g, location);
gimple_seq_add_stmt_without_update (&seq, g);
offset = gimple_assign_lhs (g);
}
/* _1 = base; */
base = unshare_expr (base);
gimple region_end =
gimple_build_assign_with_ops (TREE_CODE (base),
make_ssa_name (TREE_TYPE (base), NULL),
base, NULL);
gimple_set_location (region_end, location);
gimple_seq_add_stmt_without_update (&seq, region_end);
/* _2 = _1 + offset; */
region_end =
gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
make_ssa_name (TREE_TYPE (base), NULL),
gimple_assign_lhs (region_end),
offset);
gimple_set_location (region_end, location);
gimple_seq_add_stmt_without_update (&seq, region_end);
gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
/* instrument access at _2; */
gsi = gsi_for_stmt (region_end);
build_check_stmt (location, gimple_assign_lhs (region_end),
&gsi, /*before_p=*/false, is_store, 1);
if (then_bb == NULL)
update_mem_ref_hash_table (end, 1); update_mem_ref_hash_table (end, 1);
*iter = gsi_for_stmt (gsi_stmt (*iter)); *iter = gsi_for_stmt (gsi_stmt (*iter));
...@@ -1957,47 +2019,30 @@ instrument_strlen_call (gimple_stmt_iterator *iter) ...@@ -1957,47 +2019,30 @@ instrument_strlen_call (gimple_stmt_iterator *iter)
location_t loc = gimple_location (call); location_t loc = gimple_location (call);
tree str_arg = gimple_call_arg (call, 0); tree str_arg = gimple_call_arg (call, 0);
/* Instrument the access to the first byte of str_arg. i.e:
_1 = str_arg; instrument (_1); */
tree cptr_type = build_pointer_type (char_type_node); tree cptr_type = build_pointer_type (char_type_node);
gimple str_arg_ssa = gimple str_arg_ssa =
gimple_build_assign_with_ops (NOP_EXPR, gimple_build_assign_with_ops (NOP_EXPR,
make_ssa_name (cptr_type, NULL), make_ssa_name (cptr_type, NULL),
str_arg, NULL); str_arg, NULL);
gimple_set_location (str_arg_ssa, loc); gimple_set_location (str_arg_ssa, loc);
gimple_stmt_iterator gsi = *iter; gsi_insert_before (iter, str_arg_ssa, GSI_SAME_STMT);
gsi_insert_before (&gsi, str_arg_ssa, GSI_NEW_STMT);
build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), &gsi,
/*before_p=*/false, /*is_store=*/false, 1);
/* If we initially had an instruction like: build_check_stmt (loc, gimple_assign_lhs (str_arg_ssa), NULL_TREE, 1, iter,
/*non_zero_len_p*/true, /*before_p=*/true,
/*is_store=*/false, /*is_scalar_access*/false, /*align*/0);
int n = strlen (str)
we now want to instrument the access to str[n], after the
instruction above.*/
/* So let's build the access to str[n] that is, access through the
pointer_plus expr: (_1 + len). */
gimple stmt = gimple stmt =
gimple_build_assign_with_ops (POINTER_PLUS_EXPR, gimple_build_assign_with_ops (PLUS_EXPR,
make_ssa_name (cptr_type, NULL), make_ssa_name (TREE_TYPE (len), NULL),
gimple_assign_lhs (str_arg_ssa), len,
len); build_int_cst (TREE_TYPE (len), 1));
gimple_set_location (stmt, loc); gimple_set_location (stmt, loc);
gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); gsi_insert_after (iter, stmt, GSI_NEW_STMT);
build_check_stmt (loc, gimple_assign_lhs (stmt), &gsi, build_check_stmt (loc, gimple_assign_lhs (stmt), len, 1, iter,
/*before_p=*/false, /*is_store=*/false, 1); /*non_zero_len_p*/true, /*before_p=*/false,
/*is_store=*/false, /*is_scalar_access*/false, /*align*/0);
/* Ensure that iter points to the statement logically following the
one it was initially pointing to. */
*iter = gsi;
/* As *ITER has been advanced to point to the next statement, let's
return true to inform transform_statements that it shouldn't
advance *ITER anymore; otherwises it will skip that next
statement, which wouldn't be instrumented. */
return true; return true;
} }
...@@ -2569,6 +2614,7 @@ asan_instrument (void) ...@@ -2569,6 +2614,7 @@ asan_instrument (void)
{ {
if (shadow_ptr_types[0] == NULL_TREE) if (shadow_ptr_types[0] == NULL_TREE)
asan_init_shadow_ptr_types (); asan_init_shadow_ptr_types ();
asan_num_accesses = 0;
transform_statements (); transform_statements ();
return 0; return 0;
} }
......
...@@ -1174,7 +1174,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) ...@@ -1174,7 +1174,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
&& DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol)) && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
>= BUILT_IN_ASAN_REPORT_LOAD1 >= BUILT_IN_ASAN_REPORT_LOAD1
&& DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol)) && DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
<= BUILT_IN_ASAN_REPORT_STORE16) <= BUILT_IN_ASAN_STOREN)
return dir_none; return dir_none;
} }
} }
......
...@@ -10244,6 +10244,12 @@ is enabled by default when using @option{-fsanitize=address} option. ...@@ -10244,6 +10244,12 @@ is enabled by default when using @option{-fsanitize=address} option.
To disable use-after-return detection use To disable use-after-return detection use
@option{--param asan-use-after-return=0}. @option{--param asan-use-after-return=0}.
@item asan-instrumentation-with-call-threshold
Once number of memory accesses in function becomes greater
or equal than this number, use callbacks instead of
generating inline code. E.g. to disable inline code use
@option{--param asan-instrumentation-with-call-threshold=0}.
@end table @end table
@end table @end table
......
...@@ -1090,6 +1090,12 @@ DEFPARAM (PARAM_ASAN_USE_AFTER_RETURN, ...@@ -1090,6 +1090,12 @@ DEFPARAM (PARAM_ASAN_USE_AFTER_RETURN,
"Enable asan builtin functions protection", "Enable asan builtin functions protection",
1, 0, 1) 1, 0, 1)
DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD,
"asan-instrumentation-with-call-threshold",
"Use callbacks instead of inline code once number of accesses "
" in function becomes greater or equal than this threshold",
10000, 0, INT_MAX)
DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS, DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS,
"uninit-control-dep-attempts", "uninit-control-dep-attempts",
"Maximum number of nested calls to search for control dependencies " "Maximum number of nested calls to search for control dependencies "
......
...@@ -232,5 +232,7 @@ extern void init_param_values (int *params); ...@@ -232,5 +232,7 @@ extern void init_param_values (int *params);
PARAM_VALUE (PARAM_ASAN_MEMINTRIN) PARAM_VALUE (PARAM_ASAN_MEMINTRIN)
#define ASAN_USE_AFTER_RETURN \ #define ASAN_USE_AFTER_RETURN \
PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN) PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN)
#define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \
PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD)
#endif /* ! GCC_PARAMS_H */ #endif /* ! GCC_PARAMS_H */
...@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3. If not see
/* Address Sanitizer */ /* Address Sanitizer */
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v3", DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v3",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
/* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c /* Do not reorder the BUILT_IN_ASAN_{REPORT,CHECK}* builtins, e.g. cfgcleanup.c
relies on this order. */ relies on this order. */
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1", DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_LOAD1, "__asan_report_load1",
BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST) BT_FN_VOID_PTR, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
...@@ -57,6 +57,30 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16", ...@@ -57,6 +57,30 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE16, "__asan_report_store16",
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N, "__asan_report_store_n", DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REPORT_STORE_N, "__asan_report_store_n",
BT_FN_VOID_PTR_PTRMODE, BT_FN_VOID_PTR_PTRMODE,
ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST) ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD1, "__asan_load1",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD2, "__asan_load2",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD4, "__asan_load4",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD8, "__asan_load8",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOAD16, "__asan_load16",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_LOADN, "__asan_loadN",
BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE1, "__asan_store1",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE2, "__asan_store2",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE4, "__asan_store4",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE8, "__asan_store8",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STORE16, "__asan_store16",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_STOREN, "__asan_storeN",
BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS, DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_REGISTER_GLOBALS,
"__asan_register_globals", "__asan_register_globals",
BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
......
2014-06-16 Yury Gribov <y.gribov@samsung.com>
* c-c++-common/asan/instrument-with-calls-1.c: New test.
* c-c++-common/asan/instrument-with-calls-2.c: Likewise.
* c-c++-common/asan/instrument-with-calls-3.c: Likewise.
* c-c++-common/asan/no-redundant-instrumentation-1.c: Update
test patterns.
* c-c++-common/asan/no-redundant-instrumentation-2.c:
Likewise.
* 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.
2014-06-15 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> 2014-06-15 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR fortran/28484 PR fortran/28484
......
/* { dg-do assemble } */
/* { dg-options "--param asan-instrumentation-with-call-threshold=0 -save-temps" } */
void f(char *a, int *b) {
*b = *a;
}
/* { dg-final { scan-assembler "__asan_load1" } } */
/* { dg-final { scan-assembler "__asan_store4" } } */
/* { dg-final { cleanup-saved-temps } } */
/* { dg-do assemble } */
/* { dg-options "--param asan-instrumentation-with-call-threshold=1 -save-temps" } */
int x;
void f(int *a, int *b) {
*a = 0;
asm volatile ("" ::: "memory");
x = *b;
}
/* { dg-final { scan-assembler-not "__asan_store4" } } */
/* { dg-final { scan-assembler "__asan_report_store4" } } */
/* { dg-final { scan-assembler "__asan_load4" } } */
/* { dg-final { scan-assembler-not "__asan_report_load4" } } */
/* { dg-final { cleanup-saved-temps } } */
/* { dg-do assemble } */
/* { dg-options "--param asan-instrumentation-with-call-threshold=0 -save-temps" } */
struct A {
char x[7];
};
void f(struct A *x, struct A *y) {
*x = *y;
}
/* { dg-final { scan-assembler "__asan_loadN" } } */
/* { dg-final { scan-assembler "__asan_storeN" } } */
/* { dg-final { cleanup-saved-temps } } */
...@@ -16,12 +16,11 @@ test0 () ...@@ -16,12 +16,11 @@ test0 ()
tab[0] = 1; tab[0] = 1;
tab[1] = 2; tab[1] = 2;
/* __builtin___asan_report_load1 called 1 time for the store
below. */
char t0 = tab[1];
/* This load should not be instrumented because it is to the same /* This load should not be instrumented because it is to the same
memory location as above. */ memory location as above. */
char t0 = tab[1];
/* Likewise. */
char t1 = tab[1]; char t1 = tab[1];
return t0 + t1; return t0 + t1;
...@@ -36,7 +35,7 @@ test1 (int i) ...@@ -36,7 +35,7 @@ test1 (int i)
the initialization. */ the initialization. */
foo[i] = 1; foo[i] = 1;
/*__builtin___asan_report_store1 called 2 times here to instrument /*__builtin___asan_report_store_n called once here to instrument
the store to the memory region of tab. */ the store to the memory region of tab. */
__builtin_memset (tab, 3, sizeof (tab)); __builtin_memset (tab, 3, sizeof (tab));
...@@ -44,8 +43,8 @@ test1 (int i) ...@@ -44,8 +43,8 @@ test1 (int i)
__builtin_memset (tab, 4, sizeof (tab)); __builtin_memset (tab, 4, sizeof (tab));
__builtin_memset (tab, 5, sizeof (tab)); __builtin_memset (tab, 5, sizeof (tab));
/* There are 2 calls to __builtin___asan_report_store1 and 2 calls /* There is a call to __builtin___asan_report_store_n and a call
to __builtin___asan_report_load1 to instrument the store to to __builtin___asan_report_load_n to instrument the store to
(subset of) the memory region of tab. */ (subset of) the memory region of tab. */
__builtin_memcpy (&tab[1], foo + i, 3); __builtin_memcpy (&tab[1], foo + i, 3);
...@@ -53,7 +52,7 @@ test1 (int i) ...@@ -53,7 +52,7 @@ test1 (int i)
the reference to tab[1] has been already instrumented above. */ the reference to tab[1] has been already instrumented above. */
return tab[1]; return tab[1];
/* So for these function, there should be 7 calls to /* So for these functions, there should be 3 calls to
__builtin___asan_report_store1. */ __builtin___asan_report_store1. */
} }
...@@ -63,6 +62,7 @@ main () ...@@ -63,6 +62,7 @@ main ()
return test0 () && test1 (0); return test0 () && test1 (0);
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 7 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 3 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 2 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 1 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -20,6 +20,7 @@ main () ...@@ -20,6 +20,7 @@ main ()
__builtin_memset (tab, 1, 3); __builtin_memset (tab, 1, 3);
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 3 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 3 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report" 3 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report" 2 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -5,9 +5,13 @@ ...@@ -5,9 +5,13 @@
void void
foo (int *a, char *b, char *c) foo (int *a, char *b, char *c)
{ {
/* One check for c[0], one check for a[], one check for c, two checks for b. */
__builtin_memmove (c, b, a[c[0]]); __builtin_memmove (c, b, a[c[0]]);
/* For a total of 5 checks. */
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 3 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 1 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -5,9 +5,14 @@ ...@@ -5,9 +5,14 @@
void void
foo (int *a, char *b, char *c) 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]]); __builtin_memmove (c, b, a[b[0]]);
/* For a total of 5 checks. */
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 2 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -5,10 +5,16 @@ ...@@ -5,10 +5,16 @@
void void
foo (int *a, char *b, char *c) 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. */
__builtin_memmove (c, b, a[c[0]]); __builtin_memmove (c, b, a[c[0]]);
/* One check for a[], one check for c and one check for b. */
__builtin_memmove (c, b, a[b[0]]); __builtin_memmove (c, b, a[b[0]]);
/* For a total of 8 checks. */
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 5 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 8 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 2 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 2 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -13,11 +13,15 @@ struct S ...@@ -13,11 +13,15 @@ struct S
int int
foo (int *a, char *b, char *c) foo (int *a, char *b, char *c)
{ {
/* 2 checks for s.a, 2 checks for e. */
int d = __builtin_memcmp (s.a, e, 100); 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); d += __builtin_memcmp (s.a, e, 200);
/* For a total of 6 checks. */
return d; return d;
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load" 6 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 6 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 4 "asan0" } } */
/* { dg-final { scan-tree-dump-not "__builtin___asan_report_store" "asan0" } } */ /* { dg-final { scan-tree-dump-not "__builtin___asan_report_store" "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
...@@ -5,10 +5,16 @@ ...@@ -5,10 +5,16 @@
char char
foo (int *a, char *b, char *c) 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. */
__builtin_memmove (c, b, a[b[0]]); __builtin_memmove (c, b, a[b[0]]);
/* No checks here. */
return c[0] + b[0]; return c[0] + b[0];
/* For a total of 5 checks. */
} }
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 3 "asan0" } } */ /* { dg-final { scan-tree-dump-times "& 7" 5 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store1" 2 "asan0" } } */ /* { dg-final { scan-tree-dump-times "__builtin___asan_report_load1" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load4" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_load_n" 1 "asan0" } } */
/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 1 "asan0" } } */
/* { dg-final { cleanup-tree-dump "asan0" } } */ /* { dg-final { cleanup-tree-dump "asan0" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment