public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Xinliang David Li <davidxl@google.com>
To: Konstantin Serebryany <konstantin.s.serebryany@gmail.com>
Cc: Dodji Seketeli <dodji@redhat.com>,
	GCC Patches <gcc-patches@gcc.gnu.org>,
		Diego Novillo <dnovillo@google.com>,
	Jakub Jelinek <jakub@redhat.com>, Wei Mi <wmi@google.com>
Subject: Re: [PATCH 06/13] Implement protection of stack variables
Date: Fri, 02 Nov 2012 04:35:00 -0000	[thread overview]
Message-ID: <CAAkRFZ+mTWa3MF5D3kU9u2Xwe5zBz-k7yHUN+nj2+kDfwjCp1Q@mail.gmail.com> (raw)
In-Reply-To: <CAGQ9bdweH8Pn=8vLTNa8FSzAh92OYrWScxK78n9znCodADJUvw@mail.gmail.com>

Changing the option is part of the plan.

Dodji, can you make the option change part of one the patches (e.g,
the first one that introduces it) -- there seems no need for a
separate patch for it.

thanks,

David

On Thu, Nov 1, 2012 at 9:12 PM, Konstantin Serebryany
<konstantin.s.serebryany@gmail.com> wrote:
>
>
> On Thu, Nov 1, 2012 at 11:52 PM, <dodji@redhat.com> wrote:
>>
>> From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
>>
>> This patch implements the protection of stack variables.
>>
>> To understand how this works, lets look at this example on x86_64
>> where the stack grows downward:
>>
>>  int
>>  foo ()
>>  {
>>    char a[23] = {0};
>>    int b[2] = {0};
>>
>>    a[5] = 1;
>>    b[1] = 2;
>>
>>    return a[5] + b[1];
>>  }
>>
>> For this function, the stack protected by asan will be organized as
>> follows, from the top of the stack to the bottom:
>>
>> Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
>>
>> Slot 2/ [24 bytes for variable 'a']
>>
>> Slot 3/ [8 bytes of red zone, that adds up to the space of 'a' to make
>>          the next slot be 32 bytes aligned; this one is called Partial
>>          Redzone; this 32 bytes alignment is an asan constraint]
>>
>> Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
>>
>> Slot 5/ [8 bytes for variable 'b']
>>
>> Slot 6/ [24 bytes of Partial Red Zone (similar to slot 3]
>>
>> Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called 'LEFT
>>          RedZone']
>>
>> [A cultural question I've kept asking myself is Why has address
>>  sanitizer authors called these red zones (LEFT, MIDDLE, RIGHT)
>>  instead of e.g, (BOTTOM, MIDDLE, TOP).  Maybe they can step up and
>>  educate me so that I get less confused in the future.  :-)]
>
>
> Ha! Good question. I guess that's related to the way we explained it in the
> paper,
> where the chunk of memory was typeset horizontally to save space.
>
> Btw, are we still using -fasan option, or did we change it to
> -faddress-sanitizer?
>
> --kcc
>
>
>>
>>
>> The 32 bytes of LEFT red zone at the bottom of the stack can be
>> decomposed as such:
>>
>>     1/ The first 8 bytes contain a magical asan number that is always
>>     0x41B58AB3.
>>
>>     2/ The following 8 bytes contains a pointer to a string (to be
>>     parsed at runtime by the runtime asan library), which format is
>>     the following:
>>
>>      "<function-name> <space> <num-of-variables-on-the-stack>
>>      (<32-bytes-aligned-offset-in-bytes-of-variable> <space>
>>      <length-of-var-in-bytes> ){n} "
>>
>>         where '(...){n}' means the content inside the parenthesis occurs
>> 'n'
>>         times, with 'n' being the number of variables on the stack.
>>
>>      3/ The following 16 bytes of the red zone have no particular
>>      format.
>>
>> The shadow memory for that stack layout is going to look like this:
>>
>>     - content of shadow memory 8 bytes for slot 7: 0xFFFFFFFFF1F1F1F1.
>>       The F1 byte pattern is a magic number called
>>       ASAN_STACK_MAGIC_LEFT and is a way for the runtime to know that
>>       the memory for that shadow byte is part of a the LEFT red zone
>>       intended to seat at the bottom of the variables on the stack.
>>
>>     - content of shadow memory 8 bytes for slots 6 and 5:
>>       0xFFFFFFFFF4F4F400.  The F4 byte pattern is a magic number
>>       called ASAN_STACK_MAGIC_PARTIAL.  It flags the fact that the
>>       memory region for this shadow byte is a PARTIAL red zone
>>       intended to pad a variable A, so that the slot following
>>       {A,padding} is 32 bytes aligned.
>>
>>       Note that the fact that the least significant byte of this
>>       shadow memory content is 00 means that 8 bytes of its
>>       corresponding memory (which corresponds to the memory of
>>       variable 'b') is addressable.
>>
>>     - content of shadow memory 8 bytes for slot 4: 0xFFFFFFFFF2F2F2F2.
>>       The F2 byte pattern is a magic number called
>>       ASAN_STACK_MAGIC_MIDDLE.  It flags the fact that the memory
>>       region for this shadow byte is a MIDDLE red zone intended to
>>       seat between two 32 aligned slots of {variable,padding}.
>>
>>     - content of shadow memory 8 bytes for slot 3 and 2:
>>       0xFFFFFFFFF4000000.  This represents is the concatenation of
>>       variable 'a' and the partial red zone following it, like what we
>>       had for variable 'b'.  The least significant 3 bytes being 00
>>       means that the 3 bytes of variable 'a' are addressable.
>>
>>     - content of shadow memory 8 bytes for slot 1: 0xFFFFFFFFF3F3F3F3.
>>       The F3 byte pattern is a magic number called
>>       ASAN_STACK_MAGIC_RIGHT.  It flags the fact that the memory
>>       region for this shadow byte is a RIGHT red zone intended to seat
>>       at the top of the variables of the stack.
>>
>> So, the patch lays out stack variables as well as the different red
>> zones, emits some prologue code to populate the shadow memory as to
>> poison (mark as non-accessible) the regions of the red zones and mark
>> the regions of stack variables as accessible, and emit some epilogue
>> code to un-poison (mark as accessible) the regions of red zones right
>> before the function exits.
>>
>>         * Makefile.in (asan.o): Depend on $(EXPR_H) $(OPTABS_H).
>>         (cfgexpand.o): Depend on asan.h.
>>         * asan.c: Include expr.h and optabs.h.
>>         (asan_shadow_set): New variable.
>>         (asan_shadow_cst, asan_emit_stack_protection): New functions.
>>         (asan_init_shadow_ptr_types): Initialize also asan_shadow_set.
>>         * cfgexpand.c: Include asan.h.  Define HOST_WIDE_INT heap vector.
>>         (partition_stack_vars): If i is large alignment and j small
>>         alignment or vice versa, break out of the loop instead of
>> continue,
>>         and put the test earlier.  If flag_asan, break out of the loop
>>         if for small alignment size is different.
>>         (struct stack_vars_data): New type.
>>         (expand_stack_vars): Add DATA argument.  Change PRED type to
>>         function taking size_t argument instead of tree.  Adjust pred
>> calls.
>>         Fill DATA in and add needed padding in between variables if
>> -fasan.
>>         (defer_stack_allocation): Defer everything for flag_asan.
>>         (stack_protect_decl_phase_1, stack_protect_decl_phase_2): Take
>>         size_t index into stack_vars array instead of the decl directly.
>>         (asan_decl_phase_3): New function.
>>         (expand_used_vars): Return var destruction sequence.  Adjust
>>         expand_stack_vars calls, add another one for flag_asan.  Call
>>         asan_emit_stack_protection if expand_stack_vars added anything
>>         to the vectors.
>>         (expand_gimple_basic_block): Add disable_tail_calls argument.
>>         (gimple_expand_cfg): Pass true to it if expand_used_vars returned
>>         non-NULL.  Emit the sequence returned by expand_used_vars after
>>         return_label.
>>         * asan.h (asan_emit_stack_protection): New prototype.
>>         (asan_shadow_set): New decl.
>>         (ASAN_RED_ZONE_SIZE, ASAN_STACK_MAGIC_LEFT,
>> ASAN_STACK_MAGIC_MIDDLE,
>>         ASAN_STACK_MAGIC_RIGHT, ASAN_STACK_FRAME_MAGIC): Define.
>>         (asan_protect_stack_decl): New inline.
>>         * toplev.c (process_options): Also disable -fasan on
>>         !FRAME_GROWS_DOWNWARDS targets.
>>
>> git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/asan@192540
>> 138bc75d-0d04-0410-961f-82ee72b054a4
>> ---
>>  gcc/ChangeLog.asan |  37 ++++++++++
>>  gcc/Makefile.in    |   4 +-
>>  gcc/asan.c         | 193
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  gcc/asan.h         |  31 ++++++++-
>>  gcc/cfgexpand.c    | 159 +++++++++++++++++++++++++++++++++++++------
>>  gcc/toplev.c       |   4 +-
>>  6 files changed, 400 insertions(+), 28 deletions(-)
>>
>> diff --git a/gcc/ChangeLog.asan b/gcc/ChangeLog.asan
>> index 505bce9..23454f3 100644
>> --- a/gcc/ChangeLog.asan
>> +++ b/gcc/ChangeLog.asan
>> @@ -1,3 +1,40 @@
>> +2012-10-17  Jakub Jelinek  <jakub@redhat.com>
>> +
>> +       * Makefile.in (asan.o): Depend on $(EXPR_H) $(OPTABS_H).
>> +       (cfgexpand.o): Depend on asan.h.
>> +       * asan.c: Include expr.h and optabs.h.
>> +       (asan_shadow_set): New variable.
>> +       (asan_shadow_cst, asan_emit_stack_protection): New functions.
>> +       (asan_init_shadow_ptr_types): Initialize also asan_shadow_set.
>> +       * cfgexpand.c: Include asan.h.  Define HOST_WIDE_INT heap vector.
>> +       (partition_stack_vars): If i is large alignment and j small
>> +       alignment or vice versa, break out of the loop instead of
>> continue,
>> +       and put the test earlier.  If flag_asan, break out of the loop
>> +       if for small alignment size is different.
>> +       (struct stack_vars_data): New type.
>> +       (expand_stack_vars): Add DATA argument.  Change PRED type to
>> +       function taking size_t argument instead of tree.  Adjust pred
>> calls.
>> +       Fill DATA in and add needed padding in between variables if
>> -fasan.
>> +       (defer_stack_allocation): Defer everything for flag_asan.
>> +       (stack_protect_decl_phase_1, stack_protect_decl_phase_2): Take
>> +       size_t index into stack_vars array instead of the decl directly.
>> +       (asan_decl_phase_3): New function.
>> +       (expand_used_vars): Return var destruction sequence.  Adjust
>> +       expand_stack_vars calls, add another one for flag_asan.  Call
>> +       asan_emit_stack_protection if expand_stack_vars added anything
>> +       to the vectors.
>> +       (expand_gimple_basic_block): Add disable_tail_calls argument.
>> +       (gimple_expand_cfg): Pass true to it if expand_used_vars returned
>> +       non-NULL.  Emit the sequence returned by expand_used_vars after
>> +       return_label.
>> +       * asan.h (asan_emit_stack_protection): New prototype.
>> +       (asan_shadow_set): New decl.
>> +       (ASAN_RED_ZONE_SIZE, ASAN_STACK_MAGIC_LEFT,
>> ASAN_STACK_MAGIC_MIDDLE,
>> +       ASAN_STACK_MAGIC_RIGHT, ASAN_STACK_FRAME_MAGIC): Define.
>> +       (asan_protect_stack_decl): New inline.
>> +       * toplev.c (process_options): Also disable -fasan on
>> +       !FRAME_GROWS_DOWNWARDS targets.
>> +
>>  2012-10-12  Jakub Jelinek  <jakub@redhat.com>
>>
>>         * asan.c (build_check_stmt): Rename join_bb variable to else_bb.
>> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
>> index 2ab1ca9..2743e24 100644
>> --- a/gcc/Makefile.in
>> +++ b/gcc/Makefile.in
>> @@ -2213,7 +2213,7 @@ stor-layout.o : stor-layout.c $(CONFIG_H)
>> $(SYSTEM_H) coretypes.h $(TM_H) \
>>  asan.o : asan.c asan.h $(CONFIG_H) pointer-set.h \
>>     $(SYSTEM_H) $(TREE_H) $(GIMPLE_H) \
>>     output.h $(DIAGNOSTIC_H) coretypes.h $(TREE_DUMP_H) $(FLAGS_H) \
>> -   tree-pretty-print.h $(TARGET_H)
>> +   tree-pretty-print.h $(TARGET_H) $(EXPR_H) $(OPTABS_H)
>>  tree-ssa-tail-merge.o: tree-ssa-tail-merge.c \
>>     $(SYSTEM_H) $(CONFIG_H) coretypes.h $(TM_H) $(BITMAP_H) \
>>     $(FLAGS_H) $(TM_P_H) $(BASIC_BLOCK_H) \
>> @@ -3083,7 +3083,7 @@ cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H)
>> $(SYSTEM_H) \
>>     $(DIAGNOSTIC_H) toplev.h $(DIAGNOSTIC_CORE_H) $(BASIC_BLOCK_H)
>> $(FLAGS_H) debug.h $(PARAMS_H) \
>>     value-prof.h $(TREE_INLINE_H) $(TARGET_H) $(SSAEXPAND_H) $(REGS_H) \
>>     $(GIMPLE_PRETTY_PRINT_H) $(BITMAP_H) sbitmap.h \
>> -   $(INSN_ATTR_H) $(CFGLOOP_H)
>> +   $(INSN_ATTR_H) $(CFGLOOP_H) asan.h
>>  cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)
>> $(RTL_ERROR_H) \
>>     $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \
>>     $(FUNCTION_H) $(EXCEPT_H) $(TM_P_H) $(INSN_ATTR_H) \
>> diff --git a/gcc/asan.c b/gcc/asan.c
>> index 66dc571..fe0e9a8 100644
>> --- a/gcc/asan.c
>> +++ b/gcc/asan.c
>> @@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
>>  #include "asan.h"
>>  #include "gimple-pretty-print.h"
>>  #include "target.h"
>> +#include "expr.h"
>> +#include "optabs.h"
>>
>>  /*
>>   AddressSanitizer finds out-of-bounds and use-after-free bugs
>> @@ -79,10 +81,195 @@ along with GCC; see the file COPYING3.  If not see
>>   to create redzones for stack and global object and poison them.
>>  */
>>
>> +alias_set_type asan_shadow_set = -1;
>> +
>>  /* Pointer types to 1 resp. 2 byte integers in shadow memory.  A separate
>>     alias set is used for all shadow memory accesses.  */
>>  static GTY(()) tree shadow_ptr_types[2];
>>
>> +/* Return a CONST_INT representing 4 subsequent shadow memory bytes.  */
>> +
>> +static rtx
>> +asan_shadow_cst (unsigned char shadow_bytes[4])
>> +{
>> +  int i;
>> +  unsigned HOST_WIDE_INT val = 0;
>> +  gcc_assert (WORDS_BIG_ENDIAN == BYTES_BIG_ENDIAN);
>> +  for (i = 0; i < 4; i++)
>> +    val |= (unsigned HOST_WIDE_INT) shadow_bytes[BYTES_BIG_ENDIAN ? 3 - i
>> : i]
>> +          << (BITS_PER_UNIT * i);
>> +  return GEN_INT (trunc_int_for_mode (val, SImode));
>> +}
>> +
>> +/* 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
>> +   array contains pairs of offsets in reverse order, always the end
>> offset
>> +   of some gap that needs protection followed by starting offset,
>> +   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).  */
>> +
>> +rtx
>> +asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree
>> *decls,
>> +                           int length)
>> +{
>> +  rtx shadow_base, shadow_mem, ret, mem;
>> +  unsigned char shadow_bytes[4];
>> +  HOST_WIDE_INT base_offset = offsets[length - 1], offset, prev_offset;
>> +  HOST_WIDE_INT last_offset, last_size;
>> +  int l;
>> +  unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
>> +  static pretty_printer pp;
>> +  static bool pp_initialized;
>> +  const char *buf;
>> +  size_t len;
>> +  tree str_cst;
>> +
>> +  /* First of all, prepare the description string.  */
>> +  if (!pp_initialized)
>> +    {
>> +      pp_construct (&pp, /* prefix */NULL, /* line-width */0);
>> +      pp_initialized = true;
>> +    }
>> +  pp_clear_output_area (&pp);
>> +  if (DECL_NAME (current_function_decl))
>> +    pp_base_tree_identifier (&pp, DECL_NAME (current_function_decl));
>> +  else
>> +    pp_string (&pp, "<unknown>");
>> +  pp_space (&pp);
>> +  pp_decimal_int (&pp, length / 2 - 1);
>> +  pp_space (&pp);
>> +  for (l = length - 2; l; l -= 2)
>> +    {
>> +      tree decl = decls[l / 2 - 1];
>> +      pp_wide_integer (&pp, offsets[l] - base_offset);
>> +      pp_space (&pp);
>> +      pp_wide_integer (&pp, offsets[l - 1] - offsets[l]);
>> +      pp_space (&pp);
>> +      if (DECL_P (decl) && DECL_NAME (decl))
>> +       {
>> +         pp_decimal_int (&pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
>> +         pp_space (&pp);
>> +         pp_base_tree_identifier (&pp, DECL_NAME (decl));
>> +       }
>> +      else
>> +       pp_string (&pp, "9 <unknown>");
>> +      pp_space (&pp);
>> +    }
>> +  buf = pp_base_formatted_text (&pp);
>> +  len = strlen (buf);
>> +  str_cst = build_string (len + 1, buf);
>> +  TREE_TYPE (str_cst)
>> +    = build_array_type (char_type_node, build_index_type (size_int
>> (len)));
>> +  TREE_READONLY (str_cst) = 1;
>> +  TREE_STATIC (str_cst) = 1;
>> +  str_cst = build1 (ADDR_EXPR, build_pointer_type (char_type_node),
>> str_cst);
>> +
>> +  /* Emit the prologue sequence.  */
>> +  base = expand_binop (Pmode, add_optab, base, GEN_INT (base_offset),
>> +                      NULL_RTX, 1, OPTAB_DIRECT);
>> +  mem = gen_rtx_MEM (ptr_mode, base);
>> +  emit_move_insn (mem, GEN_INT (ASAN_STACK_FRAME_MAGIC));
>> +  mem = adjust_address (mem, VOIDmode, GET_MODE_SIZE (ptr_mode));
>> +  emit_move_insn (mem, expand_normal (str_cst));
>> +  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 (targetm.asan_shadow_offset ()),
>> +                             NULL_RTX, 1, OPTAB_DIRECT);
>> +  gcc_assert (asan_shadow_set != -1
>> +             && (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
>> +  shadow_mem = gen_rtx_MEM (SImode, shadow_base);
>> +  set_mem_alias_set (shadow_mem, asan_shadow_set);
>> +  prev_offset = base_offset;
>> +  for (l = length; l; l -= 2)
>> +    {
>> +      if (l == 2)
>> +       cur_shadow_byte = ASAN_STACK_MAGIC_RIGHT;
>> +      offset = offsets[l - 1];
>> +      if ((offset - base_offset) & (ASAN_RED_ZONE_SIZE - 1))
>> +       {
>> +         int i;
>> +         HOST_WIDE_INT aoff
>> +           = base_offset + ((offset - base_offset)
>> +                            & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
>> +         shadow_mem = adjust_address (shadow_mem, VOIDmode,
>> +                                      (aoff - prev_offset)
>> +                                      >> ASAN_SHADOW_SHIFT);
>> +         prev_offset = aoff;
>> +         for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT))
>> +           if (aoff < offset)
>> +             {
>> +               if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1)
>> +                 shadow_bytes[i] = 0;
>> +               else
>> +                 shadow_bytes[i] = offset - aoff;
>> +             }
>> +           else
>> +             shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL;
>> +         emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
>> +         offset = aoff;
>> +       }
>> +      while (offset <= offsets[l - 2] - ASAN_RED_ZONE_SIZE)
>> +       {
>> +         shadow_mem = adjust_address (shadow_mem, VOIDmode,
>> +                                      (offset - prev_offset)
>> +                                      >> ASAN_SHADOW_SHIFT);
>> +         prev_offset = offset;
>> +         memset (shadow_bytes, cur_shadow_byte, 4);
>> +         emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
>> +         offset += ASAN_RED_ZONE_SIZE;
>> +       }
>> +      cur_shadow_byte = ASAN_STACK_MAGIC_MIDDLE;
>> +    }
>> +  do_pending_stack_adjust ();
>> +
>> +  /* Construct epilogue sequence.  */
>> +  start_sequence ();
>> +
>> +  shadow_mem = gen_rtx_MEM (BLKmode, shadow_base);
>> +  set_mem_alias_set (shadow_mem, asan_shadow_set);
>> +  prev_offset = base_offset;
>> +  last_offset = base_offset;
>> +  last_size = 0;
>> +  for (l = length; l; l -= 2)
>> +    {
>> +      offset = base_offset + ((offsets[l - 1] - base_offset)
>> +                            & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
>> +      if (last_offset + last_size != offset)
>> +       {
>> +         shadow_mem = adjust_address (shadow_mem, VOIDmode,
>> +                                      (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);
>> +         last_offset = offset;
>> +         last_size = 0;
>> +       }
>> +      last_size += base_offset + ((offsets[l - 2] - base_offset)
>> +                                 & ~(ASAN_RED_ZONE_SIZE -
>> HOST_WIDE_INT_1))
>> +                  - offset;
>> +    }
>> +  if (last_size)
>> +    {
>> +      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);
>> +    }
>> +
>> +  do_pending_stack_adjust ();
>> +
>> +  ret = get_insns ();
>> +  end_sequence ();
>> +  return ret;
>> +}
>> +
>>  /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}.
>>     IS_STORE is either 1 (for a store) or 0 (for a load).
>>     SIZE_IN_BYTES is one of 1, 2, 4, 8, 16.  */
>> @@ -401,12 +588,12 @@ asan_finish_file (void)
>>  static void
>>  asan_init_shadow_ptr_types (void)
>>  {
>> -  alias_set_type set = new_alias_set ();
>> +  asan_shadow_set = new_alias_set ();
>>    shadow_ptr_types[0] = build_distinct_type_copy
>> (unsigned_char_type_node);
>> -  TYPE_ALIAS_SET (shadow_ptr_types[0]) = set;
>> +  TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set;
>>    shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]);
>>    shadow_ptr_types[1] = build_distinct_type_copy
>> (short_unsigned_type_node);
>> -  TYPE_ALIAS_SET (shadow_ptr_types[1]) = set;
>> +  TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set;
>>    shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]);
>>  }
>>
>> diff --git a/gcc/asan.h b/gcc/asan.h
>> index 0d9ab8b..6f0edbf 100644
>> --- a/gcc/asan.h
>> +++ b/gcc/asan.h
>> @@ -21,10 +21,39 @@ along with GCC; see the file COPYING3.  If not see
>>  #ifndef TREE_ASAN
>>  #define TREE_ASAN
>>
>> -extern void asan_finish_file(void);
>> +extern void asan_finish_file (void);
>> +extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *,
>> int);
>> +
>> +/* Alias set for accessing the shadow memory.  */
>> +extern alias_set_type asan_shadow_set;
>>
>>  /* Shadow memory is found at
>>     (address >> ASAN_SHADOW_SHIFT) + targetm.asan_shadow_offset ().  */
>>  #define ASAN_SHADOW_SHIFT      3
>>
>> +/* Red zone size, stack and global variables are padded by
>> ASAN_RED_ZONE_SIZE
>> +   up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes.  */
>> +#define ASAN_RED_ZONE_SIZE     32
>> +
>> +/* Shadow memory values for stack protection.  Left is below protected
>> vars,
>> +   the first pointer in stack corresponding to that offset contains
>> +   ASAN_STACK_FRAME_MAGIC word, the second pointer to a string describing
>> +   the frame.  Middle is for padding in between variables, right is
>> +   above the last protected variable and partial immediately after
>> variables
>> +   up to ASAN_RED_ZONE_SIZE alignment.  */
>> +#define ASAN_STACK_MAGIC_LEFT          0xf1
>> +#define ASAN_STACK_MAGIC_MIDDLE                0xf2
>> +#define ASAN_STACK_MAGIC_RIGHT         0xf3
>> +#define ASAN_STACK_MAGIC_PARTIAL       0xf4
>> +
>> +#define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
>> +
>> +/* Return true if DECL should be guarded on the stack.  */
>> +
>> +static inline bool
>> +asan_protect_stack_decl (tree decl)
>> +{
>> +  return DECL_P (decl) && !DECL_ARTIFICIAL (decl);
>> +}
>> +
>>  #endif /* TREE_ASAN */
>> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
>> index e501b4b..67cf902 100644
>> --- a/gcc/cfgexpand.c
>> +++ b/gcc/cfgexpand.c
>> @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
>>  #include "cfgloop.h"
>>  #include "regs.h" /* For reg_renumber.  */
>>  #include "insn-attr.h" /* For INSN_SCHEDULING.  */
>> +#include "asan.h"
>>
>>  /* This variable holds information helping the rewriting of SSA trees
>>     into RTL.  */
>> @@ -736,6 +737,7 @@ partition_stack_vars (void)
>>      {
>>        size_t i = stack_vars_sorted[si];
>>        unsigned int ialign = stack_vars[i].alignb;
>> +      HOST_WIDE_INT isize = stack_vars[i].size;
>>
>>        /* Ignore objects that aren't partition representatives. If we
>>           see a var that is not a partition representative, it must
>> @@ -747,19 +749,28 @@ partition_stack_vars (void)
>>         {
>>           size_t j = stack_vars_sorted[sj];
>>           unsigned int jalign = stack_vars[j].alignb;
>> +         HOST_WIDE_INT jsize = stack_vars[j].size;
>>
>>           /* Ignore objects that aren't partition representatives.  */
>>           if (stack_vars[j].representative != j)
>>             continue;
>>
>> -         /* Ignore conflicting objects.  */
>> -         if (stack_var_conflict_p (i, j))
>> -           continue;
>> -
>>           /* Do not mix objects of "small" (supported) alignment
>>              and "large" (unsupported) alignment.  */
>>           if ((ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
>>               != (jalign * BITS_PER_UNIT <=
>> MAX_SUPPORTED_STACK_ALIGNMENT))
>> +           break;
>> +
>> +         /* For Address Sanitizer do not mix objects with different
>> +            sizes, as the shorter vars wouldn't be adequately protected.
>> +            Don't do that for "large" (unsupported) alignment objects,
>> +            those aren't protected anyway.  */
>> +         if (flag_asan && isize != jsize
>> +             && ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
>> +           break;
>> +
>> +         /* Ignore conflicting objects.  */
>> +         if (stack_var_conflict_p (i, j))
>>             continue;
>>
>>           /* UNION the objects, placing J at OFFSET.  */
>> @@ -837,12 +848,26 @@ expand_one_stack_var_at (tree decl, rtx base,
>> unsigned base_align,
>>    set_rtl (decl, x);
>>  }
>>
>> +DEF_VEC_I(HOST_WIDE_INT);
>> +DEF_VEC_ALLOC_I(HOST_WIDE_INT,heap);
>> +
>> +struct stack_vars_data
>> +{
>> +  /* Vector of offset pairs, always end of some padding followed
>> +     by start of the padding that needs Address Sanitizer protection.
>> +     The vector is in reversed, highest offset pairs come first.  */
>> +  VEC(HOST_WIDE_INT, heap) *asan_vec;
>> +
>> +  /* Vector of partition representative decls in between the paddings.
>> */
>> +  VEC(tree, heap) *asan_decl_vec;
>> +};
>> +
>>  /* A subroutine of expand_used_vars.  Give each partition representative
>>     a unique location within the stack frame.  Update each partition
>> member
>>     with that location.  */
>>
>>  static void
>> -expand_stack_vars (bool (*pred) (tree))
>> +expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
>>  {
>>    size_t si, i, j, n = stack_vars_num;
>>    HOST_WIDE_INT large_size = 0, large_alloc = 0;
>> @@ -913,13 +938,45 @@ expand_stack_vars (bool (*pred) (tree))
>>
>>        /* Check the predicate to see whether this variable should be
>>          allocated in this pass.  */
>> -      if (pred && !pred (decl))
>> +      if (pred && !pred (i))
>>         continue;
>>
>>        alignb = stack_vars[i].alignb;
>>        if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
>>         {
>> -         offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
>> +         if (flag_asan && pred)
>> +           {
>> +             HOST_WIDE_INT prev_offset = frame_offset;
>> +             tree repr_decl = NULL_TREE;
>> +
>> +             offset
>> +               = alloc_stack_frame_space (stack_vars[i].size
>> +                                          + ASAN_RED_ZONE_SIZE,
>> +                                          MAX (alignb,
>> ASAN_RED_ZONE_SIZE));
>> +             VEC_safe_push (HOST_WIDE_INT, heap, data->asan_vec,
>> +                            prev_offset);
>> +             VEC_safe_push (HOST_WIDE_INT, heap, data->asan_vec,
>> +                            offset + stack_vars[i].size);
>> +             /* Find best representative of the partition.
>> +                Prefer those with DECL_NAME, even better
>> +                satisfying asan_protect_stack_decl predicate.  */
>> +             for (j = i; j != EOC; j = stack_vars[j].next)
>> +               if (asan_protect_stack_decl (stack_vars[j].decl)
>> +                   && DECL_NAME (stack_vars[j].decl))
>> +                 {
>> +                   repr_decl = stack_vars[j].decl;
>> +                   break;
>> +                 }
>> +               else if (repr_decl == NULL_TREE
>> +                        && DECL_P (stack_vars[j].decl)
>> +                        && DECL_NAME (stack_vars[j].decl))
>> +                 repr_decl = stack_vars[j].decl;
>> +             if (repr_decl == NULL_TREE)
>> +               repr_decl = stack_vars[i].decl;
>> +             VEC_safe_push (tree, heap, data->asan_decl_vec, repr_decl);
>> +           }
>> +         else
>> +           offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
>>           base = virtual_stack_vars_rtx;
>>           base_align = crtl->max_used_stack_slot_alignment;
>>         }
>> @@ -1057,8 +1114,9 @@ static bool
>>  defer_stack_allocation (tree var, bool toplevel)
>>  {
>>    /* If stack protection is enabled, *all* stack variables must be
>> deferred,
>> -     so that we can re-order the strings to the top of the frame.  */
>> -  if (flag_stack_protect)
>> +     so that we can re-order the strings to the top of the frame.
>> +     Similarly for Address Sanitizer.  */
>> +  if (flag_stack_protect || flag_asan)
>>      return true;
>>
>>    /* We handle "large" alignment via dynamic allocation.  We want to
>> handle
>> @@ -1329,15 +1387,31 @@ stack_protect_decl_phase (tree decl)
>>     as callbacks for expand_stack_vars.  */
>>
>>  static bool
>> -stack_protect_decl_phase_1 (tree decl)
>> +stack_protect_decl_phase_1 (size_t i)
>>  {
>> -  return stack_protect_decl_phase (decl) == 1;
>> +  return stack_protect_decl_phase (stack_vars[i].decl) == 1;
>>  }
>>
>>  static bool
>> -stack_protect_decl_phase_2 (tree decl)
>> +stack_protect_decl_phase_2 (size_t i)
>>  {
>> -  return stack_protect_decl_phase (decl) == 2;
>> +  return stack_protect_decl_phase (stack_vars[i].decl) == 2;
>> +}
>> +
>> +/* And helper function that checks for asan phase (with stack protector
>> +   it is phase 3).  This is used as callback for expand_stack_vars.
>> +   Returns true if any of the vars in the partition need to be protected.
>> */
>> +
>> +static bool
>> +asan_decl_phase_3 (size_t i)
>> +{
>> +  while (i != EOC)
>> +    {
>> +      if (asan_protect_stack_decl (stack_vars[i].decl))
>> +       return true;
>> +      i = stack_vars[i].next;
>> +    }
>> +  return false;
>>  }
>>
>>  /* Ensure that variables in different stack protection phases conflict
>> @@ -1448,11 +1522,12 @@ estimated_stack_frame_size (struct cgraph_node
>> *node)
>>
>>  /* Expand all variables used in the function.  */
>>
>> -static void
>> +static rtx
>>  expand_used_vars (void)
>>  {
>>    tree var, outer_block = DECL_INITIAL (current_function_decl);
>>    VEC(tree,heap) *maybe_local_decls = NULL;
>> +  rtx var_end_seq = NULL_RTX;
>>    struct pointer_map_t *ssa_name_decls;
>>    unsigned i;
>>    unsigned len;
>> @@ -1603,6 +1678,11 @@ expand_used_vars (void)
>>    /* Assign rtl to each variable based on these partitions.  */
>>    if (stack_vars_num > 0)
>>      {
>> +      struct stack_vars_data data;
>> +
>> +      data.asan_vec = NULL;
>> +      data.asan_decl_vec = NULL;
>> +
>>        /* Reorder decls to be protected by iterating over the variables
>>          array multiple times, and allocating out of each phase in turn.
>> */
>>        /* ??? We could probably integrate this into the qsort we did
>> @@ -1611,14 +1691,41 @@ expand_used_vars (void)
>>        if (has_protected_decls)
>>         {
>>           /* Phase 1 contains only character arrays.  */
>> -         expand_stack_vars (stack_protect_decl_phase_1);
>> +         expand_stack_vars (stack_protect_decl_phase_1, &data);
>>
>>           /* Phase 2 contains other kinds of arrays.  */
>>           if (flag_stack_protect == 2)
>> -           expand_stack_vars (stack_protect_decl_phase_2);
>> +           expand_stack_vars (stack_protect_decl_phase_2, &data);
>> +       }
>> +
>> +      if (flag_asan)
>> +       /* Phase 3, any partitions that need asan protection
>> +          in addition to phase 1 and 2.  */
>> +       expand_stack_vars (asan_decl_phase_3, &data);
>> +
>> +      if (!VEC_empty (HOST_WIDE_INT, data.asan_vec))
>> +       {
>> +         HOST_WIDE_INT prev_offset = frame_offset;
>> +         HOST_WIDE_INT offset
>> +           = alloc_stack_frame_space (ASAN_RED_ZONE_SIZE,
>> +                                      ASAN_RED_ZONE_SIZE);
>> +         VEC_safe_push (HOST_WIDE_INT, heap, data.asan_vec, prev_offset);
>> +         VEC_safe_push (HOST_WIDE_INT, heap, data.asan_vec, offset);
>> +
>> +         var_end_seq
>> +           = asan_emit_stack_protection (virtual_stack_vars_rtx,
>> +                                         VEC_address (HOST_WIDE_INT,
>> +                                                      data.asan_vec),
>> +                                         VEC_address (tree,
>> +
>> data.asan_decl_vec),
>> +                                         VEC_length (HOST_WIDE_INT,
>> +                                                     data.asan_vec));
>>         }
>>
>> -      expand_stack_vars (NULL);
>> +      expand_stack_vars (NULL, &data);
>> +
>> +      VEC_free (HOST_WIDE_INT, heap, data.asan_vec);
>> +      VEC_free (tree, heap, data.asan_decl_vec);
>>      }
>>
>>    fini_vars_expansion ();
>> @@ -1645,6 +1752,8 @@ expand_used_vars (void)
>>         frame_offset += align - 1;
>>        frame_offset &= -align;
>>      }
>> +
>> +  return var_end_seq;
>>  }
>>
>>
>> @@ -3662,7 +3771,7 @@ expand_debug_locations (void)
>>  /* Expand basic block BB from GIMPLE trees to RTL.  */
>>
>>  static basic_block
>> -expand_gimple_basic_block (basic_block bb)
>> +expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
>>  {
>>    gimple_stmt_iterator gsi;
>>    gimple_seq stmts;
>> @@ -3950,6 +4059,11 @@ expand_gimple_basic_block (basic_block bb)
>>         }
>>        else
>>         {
>> +         if (is_gimple_call (stmt)
>> +             && gimple_call_tail_p (stmt)
>> +             && disable_tail_calls)
>> +           gimple_call_set_tail (stmt, false);
>> +
>>           if (is_gimple_call (stmt) && gimple_call_tail_p (stmt))
>>             {
>>               bool can_fallthru;
>> @@ -4309,7 +4423,7 @@ gimple_expand_cfg (void)
>>    sbitmap blocks;
>>    edge_iterator ei;
>>    edge e;
>> -  rtx var_seq;
>> +  rtx var_seq, var_ret_seq;
>>    unsigned i;
>>
>>    timevar_push (TV_OUT_OF_SSA);
>> @@ -4369,7 +4483,7 @@ gimple_expand_cfg (void)
>>    timevar_push (TV_VAR_EXPAND);
>>    start_sequence ();
>>
>> -  expand_used_vars ();
>> +  var_ret_seq = expand_used_vars ();
>>
>>    var_seq = get_insns ();
>>    end_sequence ();
>> @@ -4495,7 +4609,7 @@ gimple_expand_cfg (void)
>>
>>    lab_rtx_for_bb = pointer_map_create ();
>>    FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb)
>> -    bb = expand_gimple_basic_block (bb);
>> +    bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
>>
>>    if (MAY_HAVE_DEBUG_INSNS)
>>      expand_debug_locations ();
>> @@ -4523,6 +4637,9 @@ gimple_expand_cfg (void)
>>    construct_exit_block ();
>>    insn_locations_finalize ();
>>
>> +  if (var_ret_seq)
>> +    emit_insn_after (var_ret_seq, return_label);
>> +
>>    /* Zap the tree EH table.  */
>>    set_eh_throw_stmt_table (cfun, NULL);
>>
>> diff --git a/gcc/toplev.c b/gcc/toplev.c
>> index 68849f5..0fa8ce3 100644
>> --- a/gcc/toplev.c
>> +++ b/gcc/toplev.c
>> @@ -1542,7 +1542,9 @@ process_options (void)
>>      }
>>
>>    /* Address Sanitizer needs porting to each target architecture.  */
>> -  if (flag_asan && targetm.asan_shadow_offset == NULL)
>> +  if (flag_asan
>> +      && (targetm.asan_shadow_offset == NULL
>> +         || !FRAME_GROWS_DOWNWARD))
>>      {
>>        warning (0, "-fasan not supported for this target");
>>        flag_asan = 0;
>> --
>> 1.7.11.7
>>
>

  parent reply	other threads:[~2012-11-02  4:35 UTC|newest]

Thread overview: 80+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-01 19:53 [PATCH 00/13] Request to merge Address Sanitizer in dodji
2012-11-01 19:53 ` [PATCH 07/13] Implement protection of global variables dodji
2012-11-01 19:53 ` [PATCH 02/13] Rename tree-asan.[ch] to asan.[ch] dodji
2012-11-01 21:54   ` Joseph S. Myers
2012-11-02 22:44     ` Dodji Seketeli
2012-11-01 19:53 ` [PATCH 01/13] Initial import of asan from the Google branch dodji
2012-11-01 19:53 ` [PATCH 11/13] Factorize condition insertion code out of build_check_stmt dodji
2012-11-01 19:53 ` [PATCH 12/13] Instrument built-in memory access function calls dodji
2012-11-01 19:53 ` [PATCH 09/13] Don't forget to protect 32 bytes aligned global variables dodji
2012-11-01 19:53 ` [PATCH 10/13] Make build_check_stmt accept an SSA_NAME for its base dodji
2012-11-01 19:53 ` [PATCH 03/13] Initial asan cleanups dodji
2012-11-01 19:53 ` [PATCH 05/13] Allow asan at -O0 dodji
2012-11-01 19:53 ` [PATCH 06/13] Implement protection of stack variables dodji
     [not found]   ` <CAGQ9bdweH8Pn=8vLTNa8FSzAh92OYrWScxK78n9znCodADJUvw@mail.gmail.com>
2012-11-02  4:35     ` Xinliang David Li [this message]
2012-11-02 15:25       ` Dodji Seketeli
2012-11-02 14:44     ` Dodji Seketeli
     [not found]       ` <CAGQ9bdxQG3i=BrSYmaN-ssdv4omW6F5VTg50viskKNcYrF-8BQ@mail.gmail.com>
2012-11-02 16:02         ` Dodji Seketeli
2012-11-01 19:53 ` [PATCH 08/13] Fix a couple of ICEs dodji
2012-11-01 19:54 ` [PATCH 04/13] Emit GIMPLE directly instead of gimplifying GENERIC dodji
2012-11-02 22:53 ` [PATCH 00/13] Request to merge Address Sanitizer in Dodji Seketeli
2012-11-02 22:56   ` [PATCH 01/10] Initial import of asan from the Google branch into trunk Dodji Seketeli
2012-11-06 17:04     ` Diego Novillo
2012-11-09 13:14     ` Tobias Burnus
2012-11-09 13:58       ` Jakub Jelinek
2012-11-09 16:53         ` Xinliang David Li
2012-11-09 17:13         ` Tobias Burnus
2012-11-09 17:18       ` Wei Mi
2012-11-12 11:09       ` [PATCH 03/11] Emit GIMPLE directly instead of gimplifying GENERIC Dodji Seketeli
2012-11-12 11:20       ` [PATCH 01/10] Initial import of asan from the Google branch into trunk Dodji Seketeli
2012-11-02 22:57   ` [PATCH 02/10] Initial asan cleanups Dodji Seketeli
2012-11-06 17:04     ` Diego Novillo
2012-11-12 11:12       ` Dodji Seketeli
2012-11-02 22:58   ` [PATCH 03/10] Emit GIMPLE directly instead of gimplifying GENERIC Dodji Seketeli
2012-11-06 17:08     ` Diego Novillo
2012-11-02 22:59   ` [PATCH 04/10] Allow asan at -O0 Dodji Seketeli
2012-11-06 17:12     ` Diego Novillo
2012-11-02 23:00   ` [PATCH 05/10] Implement protection of stack variables Dodji Seketeli
2012-11-06 17:22     ` Diego Novillo
2012-11-12 11:31       ` Dodji Seketeli
2012-11-12 11:51         ` Jakub Jelinek
2012-11-12 16:08           ` Dodji Seketeli
2012-11-02 23:01   ` [PATCH 06/10] Implement protection of global variables Dodji Seketeli
2012-11-06 17:27     ` Diego Novillo
2012-11-12 11:32       ` Dodji Seketeli
2012-11-02 23:02   ` [PATCH 07/10] Make build_check_stmt accept an SSA_NAME for its base Dodji Seketeli
2012-11-06 17:28     ` Diego Novillo
2012-11-02 23:03   ` [PATCH 08/10] Factorize condition insertion code out of build_check_stmt Dodji Seketeli
2012-11-05 15:50     ` Jakub Jelinek
2012-11-05 20:25       ` Dodji Seketeli
2012-11-06 17:30     ` Diego Novillo
2012-11-02 23:05   ` [PATCH 09/10] Instrument built-in memory access function calls Dodji Seketeli
2012-11-06 17:37     ` Diego Novillo
2012-11-12 11:40       ` Dodji Seketeli
2012-11-03  8:22   ` [PATCH 10/10] Import the asan runtime library into GCC tree Dodji Seketeli
     [not found]   ` <87fw4r7g8w.fsf_-_@redhat.com>
2012-11-06 17:41     ` Diego Novillo
2012-11-12 11:47       ` Dodji Seketeli
2012-11-12 18:59         ` H.J. Lu
2012-11-14 11:11           ` H.J. Lu
2012-11-14 11:42             ` H.J. Lu
2012-11-12 16:07   ` [PATCH 00/13] Request to merge Address Sanitizer in Dodji Seketeli
2012-11-12 16:21     ` Jakub Jelinek
2012-11-12 16:45       ` Tobias Burnus
2012-11-12 16:51         ` Konstantin Serebryany
2012-11-12 17:20     ` Jack Howarth
2012-11-12 17:34       ` Jack Howarth
2012-11-12 17:37         ` Tobias Burnus
2012-11-12 17:57           ` Jack Howarth
2012-11-12 17:55         ` Dodji Seketeli
2012-11-12 18:40           ` Jack Howarth
2012-11-12 20:39 ` H.J. Lu
2012-11-12 22:15   ` Ian Lance Taylor
2012-11-15 19:42 ` Jack Howarth
2012-11-15 23:42   ` Konstantin Serebryany
2012-11-16  8:27     ` Dodji Seketeli
2012-11-16 14:03       ` Jack Howarth
2012-11-16 15:57       ` Jack Howarth
2012-11-16 16:02         ` Jakub Jelinek
2012-11-16 16:47           ` Jack Howarth
2012-11-16 16:56       ` Alexander Potapenko
2012-11-16 17:06         ` Jack Howarth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAAkRFZ+mTWa3MF5D3kU9u2Xwe5zBz-k7yHUN+nj2+kDfwjCp1Q@mail.gmail.com \
    --to=davidxl@google.com \
    --cc=dnovillo@google.com \
    --cc=dodji@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=konstantin.s.serebryany@gmail.com \
    --cc=wmi@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).