ASAN: Implement dynamic allocas/VLAs sanitization.
gcc/ * asan.c: Include gimple-fold.h. (get_last_alloca_addr): New function. (handle_builtin_stackrestore): Likewise. (handle_builtin_alloca): Likewise. (asan_emit_allocas_unpoison): Likewise. (get_mem_refs_of_builtin_call): Add new parameter, remove const quallifier from first paramerer. Handle BUILT_IN_ALLOCA, BUILT_IN_ALLOCA_WITH_ALIGN and BUILT_IN_STACK_RESTORE builtins. (instrument_builtin_call): Pass gimple iterator to get_mem_refs_of_builtin_call. (last_alloca_addr): New global. * asan.h (asan_emit_allocas_unpoison): Declare. * builtins.c (expand_asan_emit_allocas_unpoison): New function. (expand_builtin): Handle BUILT_IN_ASAN_ALLOCAS_UNPOISON. * cfgexpand.c (expand_used_vars): Call asan_emit_allocas_unpoison if function calls alloca. * gimple-fold.c (replace_call_with_value): Remove static keyword. * gimple-fold.h (replace_call_with_value): Declare. * internal-fn.c: Include asan.h. * sanitizer.def (BUILT_IN_ASAN_ALLOCA_POISON, BUILT_IN_ASAN_ALLOCAS_UNPOISON): New builtins. gcc/testsuite/ * c-c++-common/asan/alloca_big_alignment.c: New test. * c-c++-common/asan/alloca_detect_custom_size.c: Likewise. * c-c++-common/asan/alloca_instruments_all_paddings.c: Likewise. * c-c++-common/asan/alloca_loop_unpoisoning.c: Likewise. * c-c++-common/asan/alloca_overflow_partial.c: Likewise. * c-c++-common/asan/alloca_overflow_right.c: Likewise. * c-c++-common/asan/alloca_safe_access.c: Likewise. * c-c++-common/asan/alloca_underflow_left.c: Likewise. From-SVN: r250031
This commit is contained in:
parent
b6f4312871
commit
e3174bdf35
@ -1,3 +1,27 @@
|
||||
2017-07-06 Maxim Ostapenko <m.ostapenko@samsung.com>
|
||||
|
||||
* asan.c: Include gimple-fold.h.
|
||||
(get_last_alloca_addr): New function.
|
||||
(handle_builtin_stackrestore): Likewise.
|
||||
(handle_builtin_alloca): Likewise.
|
||||
(asan_emit_allocas_unpoison): Likewise.
|
||||
(get_mem_refs_of_builtin_call): Add new parameter, remove const
|
||||
quallifier from first paramerer. Handle BUILT_IN_ALLOCA,
|
||||
BUILT_IN_ALLOCA_WITH_ALIGN and BUILT_IN_STACK_RESTORE builtins.
|
||||
(instrument_builtin_call): Pass gimple iterator to
|
||||
get_mem_refs_of_builtin_call.
|
||||
(last_alloca_addr): New global.
|
||||
* asan.h (asan_emit_allocas_unpoison): Declare.
|
||||
* builtins.c (expand_asan_emit_allocas_unpoison): New function.
|
||||
(expand_builtin): Handle BUILT_IN_ASAN_ALLOCAS_UNPOISON.
|
||||
* cfgexpand.c (expand_used_vars): Call asan_emit_allocas_unpoison
|
||||
if function calls alloca.
|
||||
* gimple-fold.c (replace_call_with_value): Remove static keyword.
|
||||
* gimple-fold.h (replace_call_with_value): Declare.
|
||||
* internal-fn.c: Include asan.h.
|
||||
* sanitizer.def (BUILT_IN_ASAN_ALLOCA_POISON,
|
||||
BUILT_IN_ASAN_ALLOCAS_UNPOISON): New builtins.
|
||||
|
||||
2017-07-06 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (SELFTEST_FLAGS): Drop "-x c", moving it to...
|
||||
|
215
gcc/asan.c
215
gcc/asan.c
@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "langhooks.h"
|
||||
#include "cfgloop.h"
|
||||
#include "gimple-builder.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "ubsan.h"
|
||||
#include "params.h"
|
||||
#include "builtins.h"
|
||||
@ -245,6 +246,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
static unsigned HOST_WIDE_INT asan_shadow_offset_value;
|
||||
static bool asan_shadow_offset_computed;
|
||||
static vec<char *> sanitized_sections;
|
||||
static tree last_alloca_addr;
|
||||
|
||||
/* Set of variable declarations that are going to be guarded by
|
||||
use-after-scope sanitizer. */
|
||||
@ -529,11 +531,186 @@ get_mem_ref_of_assignment (const gassign *assignment,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return address of last allocated dynamic alloca. */
|
||||
|
||||
static tree
|
||||
get_last_alloca_addr ()
|
||||
{
|
||||
if (last_alloca_addr)
|
||||
return last_alloca_addr;
|
||||
|
||||
last_alloca_addr = create_tmp_reg (ptr_type_node, "last_alloca_addr");
|
||||
gassign *g = gimple_build_assign (last_alloca_addr, null_pointer_node);
|
||||
edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
gsi_insert_on_edge_immediate (e, g);
|
||||
return last_alloca_addr;
|
||||
}
|
||||
|
||||
/* Insert __asan_allocas_unpoison (top, bottom) call after
|
||||
__builtin_stack_restore (new_sp) call.
|
||||
The pseudocode of this routine should look like this:
|
||||
__builtin_stack_restore (new_sp);
|
||||
top = last_alloca_addr;
|
||||
bot = new_sp;
|
||||
__asan_allocas_unpoison (top, bot);
|
||||
last_alloca_addr = new_sp;
|
||||
In general, we can't use new_sp as bot parameter because on some
|
||||
architectures SP has non zero offset from dynamic stack area. Moreover, on
|
||||
some architectures this offset (STACK_DYNAMIC_OFFSET) becomes known for each
|
||||
particular function only after all callees were expanded to rtl.
|
||||
The most noticeable example is PowerPC{,64}, see
|
||||
http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#DYNAM-STACK.
|
||||
To overcome the issue we use following trick: pass new_sp as a second
|
||||
parameter to __asan_allocas_unpoison and rewrite it during expansion with
|
||||
virtual_dynamic_stack_rtx later in expand_asan_emit_allocas_unpoison
|
||||
function.
|
||||
*/
|
||||
|
||||
static void
|
||||
handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
|
||||
{
|
||||
if (!iter)
|
||||
return;
|
||||
|
||||
tree last_alloca = get_last_alloca_addr ();
|
||||
tree restored_stack = gimple_call_arg (call, 0);
|
||||
tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
|
||||
gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
|
||||
gsi_insert_after (iter, g, GSI_NEW_STMT);
|
||||
g = gimple_build_assign (last_alloca, restored_stack);
|
||||
gsi_insert_after (iter, g, GSI_NEW_STMT);
|
||||
}
|
||||
|
||||
/* Deploy and poison redzones around __builtin_alloca call. To do this, we
|
||||
should replace this call with another one with changed parameters and
|
||||
replace all its uses with new address, so
|
||||
addr = __builtin_alloca (old_size, align);
|
||||
is replaced by
|
||||
left_redzone_size = max (align, ASAN_RED_ZONE_SIZE);
|
||||
Following two statements are optimized out if we know that
|
||||
old_size & (ASAN_RED_ZONE_SIZE - 1) == 0, i.e. alloca doesn't need partial
|
||||
redzone.
|
||||
misalign = old_size & (ASAN_RED_ZONE_SIZE - 1);
|
||||
partial_redzone_size = ASAN_RED_ZONE_SIZE - misalign;
|
||||
right_redzone_size = ASAN_RED_ZONE_SIZE;
|
||||
additional_size = left_redzone_size + partial_redzone_size +
|
||||
right_redzone_size;
|
||||
new_size = old_size + additional_size;
|
||||
new_alloca = __builtin_alloca (new_size, max (align, 32))
|
||||
__asan_alloca_poison (new_alloca, old_size)
|
||||
addr = new_alloca + max (align, ASAN_RED_ZONE_SIZE);
|
||||
last_alloca_addr = new_alloca;
|
||||
ADDITIONAL_SIZE is added to make new memory allocation contain not only
|
||||
requested memory, but also left, partial and right redzones as well as some
|
||||
additional space, required by alignment. */
|
||||
|
||||
static void
|
||||
handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
|
||||
{
|
||||
if (!iter)
|
||||
return;
|
||||
|
||||
gassign *g;
|
||||
gcall *gg;
|
||||
const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
|
||||
|
||||
tree last_alloca = get_last_alloca_addr ();
|
||||
tree callee = gimple_call_fndecl (call);
|
||||
tree old_size = gimple_call_arg (call, 0);
|
||||
tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
|
||||
: ptr_type_node;
|
||||
tree partial_size = NULL_TREE;
|
||||
bool alloca_with_align
|
||||
= DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA_WITH_ALIGN;
|
||||
unsigned int align
|
||||
= alloca_with_align ? tree_to_uhwi (gimple_call_arg (call, 1)) : 0;
|
||||
|
||||
/* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
|
||||
bytes of allocated space. Otherwise, align alloca to ASAN_RED_ZONE_SIZE
|
||||
manually. */
|
||||
align = MAX (align, ASAN_RED_ZONE_SIZE * BITS_PER_UNIT);
|
||||
|
||||
tree alloca_rz_mask = build_int_cst (size_type_node, redzone_mask);
|
||||
tree redzone_size = build_int_cst (size_type_node, ASAN_RED_ZONE_SIZE);
|
||||
|
||||
/* Extract lower bits from old_size. */
|
||||
wide_int size_nonzero_bits = get_nonzero_bits (old_size);
|
||||
wide_int rz_mask
|
||||
= wi::uhwi (redzone_mask, wi::get_precision (size_nonzero_bits));
|
||||
wide_int old_size_lower_bits = wi::bit_and (size_nonzero_bits, rz_mask);
|
||||
|
||||
/* If alloca size is aligned to ASAN_RED_ZONE_SIZE, we don't need partial
|
||||
redzone. Otherwise, compute its size here. */
|
||||
if (wi::ne_p (old_size_lower_bits, 0))
|
||||
{
|
||||
/* misalign = size & (ASAN_RED_ZONE_SIZE - 1)
|
||||
partial_size = ASAN_RED_ZONE_SIZE - misalign. */
|
||||
g = gimple_build_assign (make_ssa_name (size_type_node, NULL),
|
||||
BIT_AND_EXPR, old_size, alloca_rz_mask);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
tree misalign = gimple_assign_lhs (g);
|
||||
g = gimple_build_assign (make_ssa_name (size_type_node, NULL), MINUS_EXPR,
|
||||
redzone_size, misalign);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
partial_size = gimple_assign_lhs (g);
|
||||
}
|
||||
|
||||
/* additional_size = align + ASAN_RED_ZONE_SIZE. */
|
||||
tree additional_size = build_int_cst (size_type_node, align / BITS_PER_UNIT
|
||||
+ ASAN_RED_ZONE_SIZE);
|
||||
/* If alloca has partial redzone, include it to additional_size too. */
|
||||
if (partial_size)
|
||||
{
|
||||
/* additional_size += partial_size. */
|
||||
g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
|
||||
partial_size, additional_size);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
additional_size = gimple_assign_lhs (g);
|
||||
}
|
||||
|
||||
/* new_size = old_size + additional_size. */
|
||||
g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR, old_size,
|
||||
additional_size);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
tree new_size = gimple_assign_lhs (g);
|
||||
|
||||
/* Build new __builtin_alloca call:
|
||||
new_alloca_with_rz = __builtin_alloca (new_size, align). */
|
||||
tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
|
||||
gg = gimple_build_call (fn, 2, new_size,
|
||||
build_int_cst (size_type_node, align));
|
||||
tree new_alloca_with_rz = make_ssa_name (ptr_type, gg);
|
||||
gimple_call_set_lhs (gg, new_alloca_with_rz);
|
||||
gsi_insert_before (iter, gg, GSI_SAME_STMT);
|
||||
|
||||
/* new_alloca = new_alloca_with_rz + align. */
|
||||
g = gimple_build_assign (make_ssa_name (ptr_type), POINTER_PLUS_EXPR,
|
||||
new_alloca_with_rz,
|
||||
build_int_cst (size_type_node,
|
||||
align / BITS_PER_UNIT));
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
tree new_alloca = gimple_assign_lhs (g);
|
||||
|
||||
/* Poison newly created alloca redzones:
|
||||
__asan_alloca_poison (new_alloca, old_size). */
|
||||
fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCA_POISON);
|
||||
gg = gimple_build_call (fn, 2, new_alloca, old_size);
|
||||
gsi_insert_before (iter, gg, GSI_SAME_STMT);
|
||||
|
||||
/* Save new_alloca_with_rz value into last_alloca to use it during
|
||||
allocas unpoisoning. */
|
||||
g = gimple_build_assign (last_alloca, new_alloca_with_rz);
|
||||
gsi_insert_before (iter, g, GSI_SAME_STMT);
|
||||
|
||||
/* Finally, replace old alloca ptr with NEW_ALLOCA. */
|
||||
replace_call_with_value (iter, new_alloca);
|
||||
}
|
||||
|
||||
/* Return the memory references contained in a gimple statement
|
||||
representing a builtin call that has to do with memory access. */
|
||||
|
||||
static bool
|
||||
get_mem_refs_of_builtin_call (const gcall *call,
|
||||
get_mem_refs_of_builtin_call (gcall *call,
|
||||
asan_mem_ref *src0,
|
||||
tree *src0_len,
|
||||
bool *src0_is_store,
|
||||
@ -544,7 +721,8 @@ get_mem_refs_of_builtin_call (const gcall *call,
|
||||
tree *dst_len,
|
||||
bool *dst_is_store,
|
||||
bool *dest_is_deref,
|
||||
bool *intercepted_p)
|
||||
bool *intercepted_p,
|
||||
gimple_stmt_iterator *iter = NULL)
|
||||
{
|
||||
gcc_checking_assert (gimple_call_builtin_p (call, BUILT_IN_NORMAL));
|
||||
|
||||
@ -603,6 +781,14 @@ get_mem_refs_of_builtin_call (const gcall *call,
|
||||
len = gimple_call_lhs (call);
|
||||
break;
|
||||
|
||||
case BUILT_IN_STACK_RESTORE:
|
||||
handle_builtin_stack_restore (call, iter);
|
||||
break;
|
||||
|
||||
case BUILT_IN_ALLOCA_WITH_ALIGN:
|
||||
case BUILT_IN_ALLOCA:
|
||||
handle_builtin_alloca (call, iter);
|
||||
break;
|
||||
/* And now the __atomic* and __sync builtins.
|
||||
These are handled differently from the classical memory memory
|
||||
access builtins above. */
|
||||
@ -1363,6 +1549,28 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
|
||||
return insns;
|
||||
}
|
||||
|
||||
/* Emit __asan_allocas_unpoison (top, bot) call. The BASE parameter corresponds
|
||||
to BOT argument, for TOP virtual_stack_dynamic_rtx is used. NEW_SEQUENCE
|
||||
indicates whether we're emitting new instructions sequence or not. */
|
||||
|
||||
rtx_insn *
|
||||
asan_emit_allocas_unpoison (rtx top, rtx bot, rtx_insn *before)
|
||||
{
|
||||
if (before)
|
||||
push_to_sequence (before);
|
||||
else
|
||||
start_sequence ();
|
||||
rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
|
||||
ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2, top,
|
||||
TYPE_MODE (pointer_sized_int_node), bot,
|
||||
TYPE_MODE (pointer_sized_int_node));
|
||||
|
||||
do_pending_stack_adjust ();
|
||||
rtx_insn *insns = get_insns ();
|
||||
end_sequence ();
|
||||
return insns;
|
||||
}
|
||||
|
||||
/* Return true if DECL, a global var, might be overridden and needs
|
||||
therefore a local alias. */
|
||||
|
||||
@ -2002,7 +2210,7 @@ instrument_builtin_call (gimple_stmt_iterator *iter)
|
||||
&src0, &src0_len, &src0_is_store,
|
||||
&src1, &src1_len, &src1_is_store,
|
||||
&dest, &dest_len, &dest_is_store,
|
||||
&dest_is_deref, &intercepted_p))
|
||||
&dest_is_deref, &intercepted_p, iter))
|
||||
{
|
||||
if (dest_is_deref)
|
||||
{
|
||||
@ -3192,6 +3400,7 @@ asan_instrument (void)
|
||||
if (shadow_ptr_types[0] == NULL_TREE)
|
||||
asan_init_shadow_ptr_types ();
|
||||
transform_statements ();
|
||||
last_alloca_addr = NULL_TREE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ extern void asan_function_start (void);
|
||||
extern void asan_finish_file (void);
|
||||
extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
|
||||
HOST_WIDE_INT *, tree *, int);
|
||||
extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
|
||||
extern bool asan_protect_global (tree);
|
||||
extern void initialize_sanitizer_builtins (void);
|
||||
extern tree asan_dynamic_init_call (bool);
|
||||
|
@ -4962,6 +4962,26 @@ expand_builtin_alloca (tree exp)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Emit a call to __asan_allocas_unpoison call in EXP. Replace second argument
|
||||
of the call with virtual_stack_dynamic_rtx because in asan pass we emit a
|
||||
dummy value into second parameter relying on this function to perform the
|
||||
change. See motivation for this in comment to handle_builtin_stack_restore
|
||||
function. */
|
||||
|
||||
static rtx
|
||||
expand_asan_emit_allocas_unpoison (tree exp)
|
||||
{
|
||||
tree arg0 = CALL_EXPR_ARG (exp, 0);
|
||||
rtx top = expand_expr (arg0, NULL_RTX, GET_MODE (virtual_stack_dynamic_rtx),
|
||||
EXPAND_NORMAL);
|
||||
rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
|
||||
ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2, top,
|
||||
TYPE_MODE (pointer_sized_int_node),
|
||||
virtual_stack_dynamic_rtx,
|
||||
TYPE_MODE (pointer_sized_int_node));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Expand a call to bswap builtin in EXP.
|
||||
Return NULL_RTX if a normal call should be emitted rather than expanding the
|
||||
function in-line. If convenient, the result should be placed in TARGET.
|
||||
@ -6763,6 +6783,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_ASAN_ALLOCAS_UNPOISON:
|
||||
return expand_asan_emit_allocas_unpoison (exp);
|
||||
|
||||
case BUILT_IN_STACK_SAVE:
|
||||
return expand_stack_save ();
|
||||
|
||||
|
@ -2241,6 +2241,11 @@ expand_used_vars (void)
|
||||
expand_stack_vars (NULL, &data);
|
||||
}
|
||||
|
||||
if ((flag_sanitize & SANITIZE_ADDRESS) && cfun->calls_alloca)
|
||||
var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
|
||||
virtual_stack_vars_rtx,
|
||||
var_end_seq);
|
||||
|
||||
fini_vars_expansion ();
|
||||
|
||||
/* If there were any artificial non-ignored vars without rtl
|
||||
|
@ -571,7 +571,7 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
|
||||
|
||||
/* Replace the call at *GSI with the gimple value VAL. */
|
||||
|
||||
static void
|
||||
void
|
||||
replace_call_with_value (gimple_stmt_iterator *gsi, tree val)
|
||||
{
|
||||
gimple *stmt = gsi_stmt (*gsi);
|
||||
|
@ -58,6 +58,7 @@ extern bool gimple_fold_builtin_sprintf (gimple_stmt_iterator *);
|
||||
extern bool gimple_fold_builtin_snprintf (gimple_stmt_iterator *);
|
||||
extern bool arith_code_with_undefined_signed_overflow (tree_code);
|
||||
extern gimple_seq rewrite_to_defined_overflow (gimple *);
|
||||
extern void replace_call_with_value (gimple_stmt_iterator *, tree);
|
||||
|
||||
/* gimple_build, functionally matching fold_buildN, outputs stmts
|
||||
int the provided sequence, matching and simplifying them on-the-fly.
|
||||
|
@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "stor-layout.h"
|
||||
#include "dojump.h"
|
||||
#include "expr.h"
|
||||
#include "asan.h"
|
||||
#include "ubsan.h"
|
||||
#include "recog.h"
|
||||
#include "builtins.h"
|
||||
|
@ -171,6 +171,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POISON_STACK_MEMORY,
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNPOISON_STACK_MEMORY,
|
||||
"__asan_unpoison_stack_memory",
|
||||
BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCA_POISON, "__asan_alloca_poison",
|
||||
BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_ALLOCAS_UNPOISON, "__asan_allocas_unpoison",
|
||||
BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
|
||||
|
||||
/* Thread Sanitizer */
|
||||
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
|
||||
|
@ -1,3 +1,14 @@
|
||||
2017-07-06 Maxim Ostapenko <m.ostapenko@samsung.com>
|
||||
|
||||
* c-c++-common/asan/alloca_big_alignment.c: New test.
|
||||
* c-c++-common/asan/alloca_detect_custom_size.c: Likewise.
|
||||
* c-c++-common/asan/alloca_instruments_all_paddings.c: Likewise.
|
||||
* c-c++-common/asan/alloca_loop_unpoisoning.c: Likewise.
|
||||
* c-c++-common/asan/alloca_overflow_partial.c: Likewise.
|
||||
* c-c++-common/asan/alloca_overflow_right.c: Likewise.
|
||||
* c-c++-common/asan/alloca_safe_access.c: Likewise.
|
||||
* c-c++-common/asan/alloca_underflow_left.c: Likewise.
|
||||
|
||||
2017-07-06 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR target/81305
|
||||
|
22
gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c
Normal file
22
gcc/testsuite/c-c++-common/asan/alloca_big_alignment.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-shouldfail "asan" } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
volatile int ten = 10;
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(128)));
|
||||
assert(!((long) str & 127L));
|
||||
str[index] = '1'; // BOOM
|
||||
}
|
||||
|
||||
int main() {
|
||||
foo(ten, ten);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_big_alignment.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
|
||||
/* { dg-output "\[^\n\r]*in foo.*alloca_big_alignment.c.*(\n|\r\n|\r)" */
|
27
gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c
Normal file
27
gcc/testsuite/c-c++-common/asan/alloca_detect_custom_size.c
Normal file
@ -0,0 +1,27 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-shouldfail "asan" } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
struct A {
|
||||
char a[3];
|
||||
int b[3];
|
||||
};
|
||||
|
||||
volatile int ten = 10;
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile struct A str[len] __attribute__((aligned(32)));
|
||||
assert(!((long) str & 31L));
|
||||
str[index].a[0] = '1'; // BOOM
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(ten, ten);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_detect_custom_size.c:16|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
|
||||
/* { dg-output "\[^\n\r]*in foo.*alloca_detect_custom_size.c.*(\n|\r\n|\r)" */
|
@ -0,0 +1,21 @@
|
||||
/* { dg-do run } */
|
||||
|
||||
#include "sanitizer/asan_interface.h"
|
||||
#include <assert.h>
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(32)));
|
||||
assert(!((long) str & 31L));
|
||||
char *q = (char *)__asan_region_is_poisoned((char *)str, 64);
|
||||
assert(q && ((q - str) == index));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
for (int i = 1; i < 33; ++i)
|
||||
foo(i, i);
|
||||
|
||||
for (int i = 1; i < 33; ++i)
|
||||
foo(i, i);
|
||||
|
||||
return 0;
|
||||
}
|
34
gcc/testsuite/c-c++-common/asan/alloca_loop_unpoisoning.c
Normal file
34
gcc/testsuite/c-c++-common/asan/alloca_loop_unpoisoning.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* { dg-do run } */
|
||||
|
||||
/* This testcase checks that allocas and VLAs inside loop are correctly unpoisoned. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
void *top, *bot;
|
||||
volatile int thirty_two = 32;
|
||||
|
||||
__attribute__((noinline)) void foo(int len) {
|
||||
char x;
|
||||
top = &x;
|
||||
volatile char array[len];
|
||||
assert(!((uintptr_t) array & 31L));
|
||||
alloca(len);
|
||||
for (int i = 0; i < thirty_two; ++i) {
|
||||
char array[i];
|
||||
bot = array;
|
||||
/* Just to prevent optimization. */
|
||||
printf("%p\n", bot);
|
||||
assert(!((uintptr_t) bot & 31L));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(thirty_two);
|
||||
void *q = __asan_region_is_poisoned(bot, (char *)top - (char *)bot);
|
||||
assert(!q);
|
||||
return 0;
|
||||
}
|
22
gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c
Normal file
22
gcc/testsuite/c-c++-common/asan/alloca_overflow_partial.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-shouldfail "asan" } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
volatile const int ten = 10;
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(32)));
|
||||
assert(!((long) str & 31L));
|
||||
str[index] = '1'; // BOOM
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(ten, ten);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_partial.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
|
||||
/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_partial.c.*(\n|\r\n|\r)" */
|
22
gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c
Normal file
22
gcc/testsuite/c-c++-common/asan/alloca_overflow_right.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-shouldfail "asan" } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
volatile const int ten = 10;
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(32)));
|
||||
assert(!((long) str & 31L));
|
||||
str[index] = '1'; // BOOM
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(33, ten);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_overflow_right.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
|
||||
/* { dg-output "\[^\n\r]*in foo.*alloca_overflow_right.c.*(\n|\r\n|\r)" */
|
15
gcc/testsuite/c-c++-common/asan/alloca_safe_access.c
Normal file
15
gcc/testsuite/c-c++-common/asan/alloca_safe_access.c
Normal file
@ -0,0 +1,15 @@
|
||||
/* { dg-do run } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(32)));
|
||||
assert(!((long)str & 31L));
|
||||
str[index] = '1';
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(4, 5);
|
||||
foo(39, 40);
|
||||
return 0;
|
||||
}
|
22
gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c
Normal file
22
gcc/testsuite/c-c++-common/asan/alloca_underflow_left.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-shouldfail "asan" } */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
volatile const int ten = 10;
|
||||
|
||||
__attribute__((noinline)) void foo(int index, int len) {
|
||||
volatile char str[len] __attribute__((aligned(32)));
|
||||
assert(!((long) str & 31L));
|
||||
str[index] = '1'; // BOOM
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
foo(-1, ten);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ +(in _*foo(\[^\n\r]*alloca_underflow_left.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "\[^\n\r]*Address 0x\[0-9a-f\]+ is located in stack of thread T0.*(\n|\r\n|\r)" */
|
||||
/* { dg-output "\[^\n\r]*in foo.*alloca_underflow_left.c.*(\n|\r\n|\r)" */
|
Loading…
x
Reference in New Issue
Block a user