gcc/ChangeLog:
2014-10-17 Max Ostapenko <m.ostapenko@partner.samsung.com>
* 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.
(instrument_mem_region_access): Likewise.
(instrument_builtin_call): Call maybe_update_mem_ref_hash_table instead
of instrument_mem_region_access.
* builtins.c (is_memory_builtin): New function.
(expand_builtin): Don't expand string/memory builtin functions if ASan
is enabled.
* builtins.def: Add comment.
gcc/testsuite/ChangeLog:
2014-10-17 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.
@@ -352,10 +352,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
@@ -365,8 +362,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;
@@ -417,7 +413,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. */
@@ -434,19 +431,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;
-
- 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;
+ HOST_WIDE_INT size_in_bytes
+ = tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+ if (size_in_bytes != -1)
+ return has_mem_ref_been_instrumented (ref->start, size_in_bytes);
+ return false;
}
/* Set REF to the memory reference present in a gimple assignment
@@ -870,7 +859,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);
}
@@ -1784,113 +1773,21 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
}
-/* 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
- which the instrumentation instructions must be inserted. LOCATION
- is the source location that the instrumentation instructions must
- have. If IS_STORE is true, then the memory access is a store;
- otherwise, it's a load. */
+/* Insert a memory reference into the hash table if access length
+ can be determined in compile time. */
static void
-instrument_mem_region_access (tree base, tree len,
- gimple_stmt_iterator *iter,
- location_t location, bool is_store)
+maybe_update_mem_ref_hash_table (tree base, tree len)
{
if (!POINTER_TYPE_P (TREE_TYPE (base))
- || !INTEGRAL_TYPE_P (TREE_TYPE (len))
- || integer_zerop (len))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (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);
-
- *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;
+ if ((size_in_bytes != -1)
+ && !has_mem_ref_been_instrumented (base, size_in_bytes))
+ update_mem_ref_hash_table (base, size_in_bytes);
}
/* Instrument the call to a built-in memory access function that is
@@ -1910,50 +1807,41 @@ 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);
+ 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;
+ 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;
+ bool 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 (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
+ {
+ gsi_next (iter);
+ iter_advanced_p = true;
+
+ 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;
}
@@ -5747,6 +5747,15 @@ expand_stack_save (void)
return ret;
}
+/* Returns TRUE if given FCODE corresponds to string or memory builtin function.
+ */
+
+static inline bool
+is_memory_builtin (enum built_in_function fcode)
+{
+ return fcode <= BUILT_IN_STRSTR && fcode >= BUILT_IN_BCMP;
+}
+
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
(and in mode MODE if that's convenient).
@@ -5762,6 +5771,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
int flags;
+ if ((flag_sanitize & SANITIZE_ADDRESS)
+ && is_memory_builtin (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);
@@ -569,7 +569,11 @@ DEF_C99_COMPL_BUILTIN (BUILT_IN_CTANL, "ctanl", BT_FN_COMPLEX_LONGDOUBLE_
/* Category: string/memory builtins. */
/* bcmp, bcopy and bzero have traditionally accepted NULL pointers
- when the length parameter is zero, so don't apply attribute "nonnull". */
+ when the length parameter is zero, so don't apply attribute "nonnull".
+ Do not reorder the BUILT_IN_* builtins, e.g. builtins.c relies on this
+ order. If you want to add a new string/memory builtin, please insert
+ it after BUILT_IN_BCMP and before BUILT_IN_STRSTR. */
+
DEF_EXT_LIB_BUILTIN (BUILT_IN_BCMP, "bcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_BCOPY, "bcopy", BT_FN_VOID_CONST_PTR_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHROW_LEAF_LIST)
@@ -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" } } */
new file mode 100644
@@ -0,0 +1,18 @@
+/* { dg-options "-fdump-tree-sanopt" } */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+
+extern __UINT32_TYPE__ a;
+
+void
+foo ()
+{
+ /* Instrument a with access size 3. */
+ int d = __builtin_memcmp (&a, "123", 3);
+ /* This should generate a __builtin___asan_report_store4, because
+ the reference to a has been instrumented above with access size 3. */
+ a = 1;
+}
+
+/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store4" 1 "sanopt" } } */
+/* { dg-final { cleanup-tree-dump "sanopt" } } */
new file mode 100644
@@ -0,0 +1,20 @@
+/* { dg-options "-fdump-tree-sanopt" } */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+
+extern __UINT32_TYPE__ a;
+
+void
+foo ()
+{
+ /* Instrument a with access size 5. */
+ int d = __builtin_memcmp (&a, "12345", 4);
+ /* This should not generate a __builtin___asan_report_store4 because
+ the reference to a has been already instrumented above with access
+ size 5. */
+ a = 1;
+}
+
+/* { dg-final { scan-tree-dump-not "& 7" "sanopt" } } */
+/* { dg-final { scan-tree-dump-not "__builtin___asan_report_store" "sanopt" } } */
+/* { dg-final { cleanup-tree-dump "sanopt" } } */
deleted file mode 100644
@@ -1,26 +0,0 @@
-/* This tests that when faced with two references to the same memory
- location in the same basic block, the second reference should not
- be instrumented by the Address Sanitizer. But in case of access to
- overlapping regions we must be precise. */
-
-/* { dg-options "-fdump-tree-sanopt" } */
-/* { dg-do compile } */
-/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
-
-int
-main ()
-{
- char tab[5];
-
- /* Here, we instrument the access at offset 0 and access at offset
- 4. */
- __builtin_memset (tab, 1, sizeof (tab));
- /* We instrumented access at offset 0 above already, so only access
- at offset 3 is instrumented. */
- __builtin_memset (tab, 1, 3);
-}
-
-/* { dg-final { scan-tree-dump-times "& 7" 3 "sanopt" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report_store_n" 2 "sanopt" } } */
-/* { dg-final { scan-tree-dump-times "__builtin___asan_report" 2 "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" } } */
deleted file mode 100644
@@ -1,13 +0,0 @@
-/* { dg-options "-fdump-tree-sanopt" } */
-/* { dg-do compile } */
-/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
-
-__SIZE_TYPE__
-f (char *a)
-{
- a[0] = '1';
- return __builtin_strlen (a);
-}
-
-/* { dg-final { scan-tree-dump-times "__asan_report_load1" 1 "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" } */