summaryrefslogtreecommitdiff
path: root/gcc/asan.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-28 08:18:59 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-28 08:18:59 +0000
commit683539f6f6040795b4e06d79bd591fa1ce70b234 (patch)
treeb8e14dee616a6f5428fd7b804709a5da8b7d3073 /gcc/asan.c
parent3e398f5b1e7be2eb13b2a2d0cdd647920ae60e37 (diff)
downloadgcc-683539f6f6040795b4e06d79bd591fa1ce70b234.tar.gz
* cfgexpand.c (struct stack_vars_data): Add asan_base and asan_alignb
fields. (expand_stack_vars): For -fsanitize=address, use (and set initially) data->asan_base as base for vars and update asan_alignb. (expand_used_vars): Initialize data.asan_base and data.asan_alignb. Pass them to asan_emit_stack_protection. * asan.c (asan_detect_stack_use_after_return): New variable. (asan_emit_stack_protection): Add pbase and alignb arguments. Implement use after return sanitization. * asan.h (asan_emit_stack_protection): Adjust prototype. (ASAN_STACK_MAGIC_USE_AFTER_RET, ASAN_STACK_RETIRED_MAGIC): Define. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205476 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/asan.c')
-rw-r--r--gcc/asan.c129
1 files changed, 119 insertions, 10 deletions
diff --git a/gcc/asan.c b/gcc/asan.c
index 677435e05ae..2245d6dd807 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -237,6 +237,9 @@ alias_set_type asan_shadow_set = -1;
alias set is used for all shadow memory accesses. */
static GTY(()) tree shadow_ptr_types[2];
+/* Decl for __asan_option_detect_stack_use_after_return. */
+static GTY(()) tree asan_detect_stack_use_after_return;
+
/* Hashtable support for memory references used by gimple
statements. */
@@ -950,20 +953,26 @@ asan_function_start (void)
and DECLS is an array of representative decls for each var partition.
LENGTH is the length of the OFFSETS array, DECLS array is LENGTH / 2 - 1
elements long (OFFSETS include gap before the first variable as well
- as gaps after each stack variable). */
+ as gaps after each stack variable). PBASE is, if non-NULL, some pseudo
+ register which stack vars DECL_RTLs are based on. Either BASE should be
+ assigned to PBASE, when not doing use after return protection, or
+ corresponding address based on __asan_stack_malloc* return value. */
rtx
-asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
- int length)
+asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
+ HOST_WIDE_INT *offsets, tree *decls, int length)
{
- rtx shadow_base, shadow_mem, ret, mem;
+ rtx shadow_base, shadow_mem, ret, mem, orig_base, lab;
char buf[30];
unsigned char shadow_bytes[4];
- HOST_WIDE_INT base_offset = offsets[length - 1], offset, prev_offset;
+ HOST_WIDE_INT base_offset = offsets[length - 1];
+ HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
+ HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
HOST_WIDE_INT last_offset, last_size;
int l;
unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
tree str_cst, decl, id;
+ int use_after_return_class = -1;
if (shadow_ptr_types[0] == NULL_TREE)
asan_init_shadow_ptr_types ();
@@ -993,10 +1002,67 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
str_cst = asan_pp_string (&asan_pp);
/* Emit the prologue sequence. */
+ if (asan_frame_size > 32 && asan_frame_size <= 65536 && pbase)
+ {
+ use_after_return_class = floor_log2 (asan_frame_size - 1) - 5;
+ /* __asan_stack_malloc_N guarantees alignment
+ N < 6 ? (64 << N) : 4096 bytes. */
+ if (alignb > (use_after_return_class < 6
+ ? (64U << use_after_return_class) : 4096U))
+ use_after_return_class = -1;
+ else if (alignb > ASAN_RED_ZONE_SIZE && (asan_frame_size & (alignb - 1)))
+ base_align_bias = ((asan_frame_size + alignb - 1)
+ & ~(alignb - HOST_WIDE_INT_1)) - asan_frame_size;
+ }
+ if (use_after_return_class == -1 && pbase)
+ emit_move_insn (pbase, base);
base = expand_binop (Pmode, add_optab, base,
- gen_int_mode (base_offset, Pmode),
+ gen_int_mode (base_offset - base_align_bias, Pmode),
NULL_RTX, 1, OPTAB_DIRECT);
+ orig_base = NULL_RTX;
+ if (use_after_return_class != -1)
+ {
+ if (asan_detect_stack_use_after_return == NULL_TREE)
+ {
+ id = get_identifier ("__asan_option_detect_stack_use_after_return");
+ decl = build_decl (BUILTINS_LOCATION, VAR_DECL, id,
+ integer_type_node);
+ SET_DECL_ASSEMBLER_NAME (decl, id);
+ TREE_ADDRESSABLE (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ asan_detect_stack_use_after_return = decl;
+ }
+ orig_base = gen_reg_rtx (Pmode);
+ emit_move_insn (orig_base, base);
+ ret = expand_normal (asan_detect_stack_use_after_return);
+ lab = gen_label_rtx ();
+ int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
+ emit_cmp_and_jump_insns (ret, const0_rtx, EQ, NULL_RTX,
+ VOIDmode, 0, lab, very_likely);
+ snprintf (buf, sizeof buf, "__asan_stack_malloc_%d",
+ use_after_return_class);
+ ret = init_one_libfunc (buf);
+ rtx addr = convert_memory_address (ptr_mode, base);
+ ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2,
+ GEN_INT (asan_frame_size
+ + base_align_bias),
+ TYPE_MODE (pointer_sized_int_node),
+ addr, ptr_mode);
+ ret = convert_memory_address (Pmode, ret);
+ emit_move_insn (base, ret);
+ emit_label (lab);
+ emit_move_insn (pbase, expand_binop (Pmode, add_optab, base,
+ gen_int_mode (base_align_bias
+ - base_offset, Pmode),
+ NULL_RTX, 1, OPTAB_DIRECT));
+ }
mem = gen_rtx_MEM (ptr_mode, base);
+ mem = adjust_address (mem, VOIDmode, base_align_bias);
emit_move_insn (mem, gen_int_mode (ASAN_STACK_FRAME_MAGIC, ptr_mode));
mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
emit_move_insn (mem, expand_normal (str_cst));
@@ -1020,10 +1086,10 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
shadow_base = expand_binop (Pmode, lshr_optab, base,
GEN_INT (ASAN_SHADOW_SHIFT),
NULL_RTX, 1, OPTAB_DIRECT);
- shadow_base = expand_binop (Pmode, add_optab, shadow_base,
- gen_int_mode (targetm.asan_shadow_offset (),
- Pmode),
- NULL_RTX, 1, OPTAB_DIRECT);
+ shadow_base
+ = plus_constant (Pmode, shadow_base,
+ targetm.asan_shadow_offset ()
+ + (base_align_bias >> ASAN_SHADOW_SHIFT));
gcc_assert (asan_shadow_set != -1
&& (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
shadow_mem = gen_rtx_MEM (SImode, shadow_base);
@@ -1074,6 +1140,47 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
/* Construct epilogue sequence. */
start_sequence ();
+ lab = NULL_RTX;
+ if (use_after_return_class != -1)
+ {
+ rtx lab2 = gen_label_rtx ();
+ char c = (char) ASAN_STACK_MAGIC_USE_AFTER_RET;
+ int very_likely = REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1);
+ emit_cmp_and_jump_insns (orig_base, base, EQ, NULL_RTX,
+ VOIDmode, 0, lab2, very_likely);
+ shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
+ set_mem_alias_set (shadow_mem, asan_shadow_set);
+ mem = gen_rtx_MEM (ptr_mode, base);
+ mem = adjust_address (mem, VOIDmode, base_align_bias);
+ emit_move_insn (mem, gen_int_mode (ASAN_STACK_RETIRED_MAGIC, ptr_mode));
+ unsigned HOST_WIDE_INT sz = asan_frame_size >> ASAN_SHADOW_SHIFT;
+ if (use_after_return_class < 5
+ && can_store_by_pieces (sz, builtin_memset_read_str, &c,
+ BITS_PER_UNIT, true))
+ store_by_pieces (shadow_mem, sz, builtin_memset_read_str, &c,
+ BITS_PER_UNIT, true, 0);
+ else if (use_after_return_class >= 5
+ || !set_storage_via_setmem (shadow_mem,
+ GEN_INT (sz),
+ gen_int_mode (c, QImode),
+ BITS_PER_UNIT, BITS_PER_UNIT,
+ -1, sz, sz, sz))
+ {
+ snprintf (buf, sizeof buf, "__asan_stack_free_%d",
+ use_after_return_class);
+ ret = init_one_libfunc (buf);
+ rtx addr = convert_memory_address (ptr_mode, base);
+ rtx orig_addr = convert_memory_address (ptr_mode, orig_base);
+ emit_library_call (ret, LCT_NORMAL, ptr_mode, 3, addr, ptr_mode,
+ GEN_INT (asan_frame_size + base_align_bias),
+ TYPE_MODE (pointer_sized_int_node),
+ orig_addr, ptr_mode);
+ }
+ lab = gen_label_rtx ();
+ emit_jump (lab);
+ emit_label (lab2);
+ }
+
shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
set_mem_alias_set (shadow_mem, asan_shadow_set);
prev_offset = base_offset;
@@ -1106,6 +1213,8 @@ asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
}
do_pending_stack_adjust ();
+ if (lab)
+ emit_label (lab);
ret = get_insns ();
end_sequence ();