From patchwork Wed Dec 19 12:10:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [asan] Never use memset for clearing of shadow mem in epilogues (PR fortran/55341) Date: Wed, 19 Dec 2012 02:10:38 -0000 From: Jakub Jelinek X-Patchwork-Id: 207327 Message-Id: <20121219121038.GW2315@tucnak.redhat.com> To: Konstantin Serebryany , Dmitry Vyukov , Dodji Seketeli Cc: gcc-patches@gcc.gnu.org Hi! clear_storage sometimes emits a library call instead of clearing storage by pieces, rep stos* and similar, unfortunately if it is a call that libasan intercepts (memset), it fails because it doesn't allow writes into shadow mem. Fixed by scanning the clear_storage sequence if there are any calls, and if there are, replaces it with a simple loop storing 0. Tested on x86_64-linux, ok for trunk? 2012-12-19 Jakub Jelinek PR fortran/55341 * asan.c (asan_clear_shadow): New function. (asan_emit_stack_protection): Use it. Jakub --- gcc/asan.c.jj 2012-12-13 00:05:04.000000000 +0100 +++ gcc/asan.c 2012-12-19 12:25:57.676365851 +0100 @@ -270,6 +270,45 @@ asan_shadow_cst (unsigned char shadow_by return GEN_INT (trunc_int_for_mode (val, SImode)); } +/* Clear shadow memory at SHADOW_MEM, LEN bytes. Can't call a library call here + though. */ + +static void +asan_clear_shadow (rtx shadow_mem, HOST_WIDE_INT len) +{ + rtx insn, insns, top_label, end, addr, tmp, jump; + + start_sequence (); + clear_storage (shadow_mem, GEN_INT (len), BLOCK_OP_NORMAL); + insns = get_insns (); + end_sequence (); + for (insn = insns; insn; insn = NEXT_INSN (insn)) + if (CALL_P (insn)) + break; + if (insn == NULL_RTX) + { + emit_insn (insns); + return; + } + + gcc_assert ((len & 3) == 0); + top_label = gen_label_rtx (); + addr = force_reg (Pmode, XEXP (shadow_mem, 0)); + shadow_mem = adjust_automodify_address (shadow_mem, SImode, addr, 0); + end = force_reg (Pmode, plus_constant (Pmode, addr, len)); + emit_label (top_label); + + emit_move_insn (shadow_mem, const0_rtx); + tmp = expand_simple_binop (Pmode, PLUS, addr, GEN_INT (4), addr, + true, OPTAB_LIB_WIDEN); + if (tmp != addr) + emit_move_insn (addr, tmp); + emit_cmp_and_jump_insns (addr, end, LT, NULL_RTX, Pmode, true, top_label); + jump = get_last_insn (); + gcc_assert (JUMP_P (jump)); + add_reg_note (jump, REG_BR_PROB, GEN_INT (REG_BR_PROB_BASE * 80 / 100)); +} + /* Insert code to protect stack vars. The prologue sequence should be emitted directly, epilogue sequence returned. BASE is the register holding the stack base, against which OFFSETS array offsets are relative to, OFFSETS @@ -404,8 +443,7 @@ asan_emit_stack_protection (rtx base, HO (last_offset - prev_offset) >> ASAN_SHADOW_SHIFT); prev_offset = last_offset; - clear_storage (shadow_mem, GEN_INT (last_size >> ASAN_SHADOW_SHIFT), - BLOCK_OP_NORMAL); + asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); last_offset = offset; last_size = 0; } @@ -418,8 +456,7 @@ asan_emit_stack_protection (rtx base, HO shadow_mem = adjust_address (shadow_mem, VOIDmode, (last_offset - prev_offset) >> ASAN_SHADOW_SHIFT); - clear_storage (shadow_mem, GEN_INT (last_size >> ASAN_SHADOW_SHIFT), - BLOCK_OP_NORMAL); + asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); } do_pending_stack_adjust ();