RE: [PATCH] asan, v3: Fix up handling of > 32 byte aligned variables with -fsanitize=address -fstack-protector* [PR110027]

2024-04-11 Thread Liu, Hongtao



> -Original Message-
> From: Jakub Jelinek 
> Sent: Thursday, April 11, 2024 4:39 PM
> To: Richard Biener ; Jeff Law ;
> Liu, Hongtao 
> Cc: gcc-patches@gcc.gnu.org
> Subject: [PATCH] asan, v3: Fix up handling of > 32 byte aligned variables 
> with -
> fsanitize=address -fstack-protector* [PR110027]
> 
> On Tue, Mar 26, 2024 at 02:08:02PM +0800, liuhongt wrote:
> > > > So, try to add some other variable with larger size and smaller
> > > > alignment to the frame (and make sure it isn't optimized away).
> > > >
> > > > alignb above is the alignment of the first partition's var, if
> > > > align_frame_offset really needs to depend on the var alignment, it
> > > > probably should be the maximum alignment of all the vars with
> > > > alignment alignb * BITS_PER_UNIT <=3D
> > > > MAX_SUPPORTED_STACK_ALIGNMENT
> > > >
> >
> > In asan_emit_stack_protection, when it allocated fake stack, it assume
> > bottom of stack is also aligned to alignb. And the place violated this
> > is the first var partition. which is 32 bytes offsets,  it should be
> > BIGGEST_ALIGNMENT / BITS_PER_UNIT.
> > So I think we need to use MAX (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
> > ASAN_RED_ZONE_SIZE) for the first var partition.
> 
> Your first patch aligned offsets[0] to maximum of alignb and
> ASAN_RED_ZONE_SIZE.  But as I wrote in the reply to that mail, alignb there is
> the alignment of just a single variable which is the first one to appear in 
> the
> sorted list and is placed in the highest spot in the stack frame.
> That is not necessarily the largest alignment, the sorting ensures that it is 
> a
> variable with the largest size in the frame (and only if several of them have
> equal size, largest alignment from the same sized ones).  Your second patch
> used maximum of BIGGEST_ALIGNMENT / BITS_PER_UNIT and
> ASAN_RED_ZONE_SIZE.  That doesn't change anything at all when using -mno-
> avx512f - offsets[0] is still just 32-byte aligned in that case relative to 
> top of
> frame, just changes the -mavx512f case to be 64-byte aligned offsets[0] (aka
> offsets[0] is then either 0 or -64 instead of either
> 0 or -32).  That will not help if any variable in the frame needs 128-byte, 
> 256-
> byte, 512-byte ...  4096-byte alignment.  If you want to fix the bug in the 
> spot
> you've touched, you'd need to walk all the stack_vars[stack_vars_sorted[si2]]
> for si2 [si + 1, n - 1] and for those where the loop would do anything (i.e.
> stack_vars[i2].representative == i2
> && TREE_CODE (decl2) == SSA_NAME
>? SA.partition_to_pseudo[var_to_partition (SA.map, decl2)] == NULL_RTX
>: DECL_RTL (decl2) == pc_rtx
> and the pred applies (but that means also walking the earlier ones!
> because with -fstack-protector* the vars can be processed in several calls) 
> and
> alignb2 * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT and
> compute maximum of those alignments.
> That maximum is already computed,
> data->asan_alignb = MAX (data->asan_alignb, alignb);
> computes that, but you get the final result only after you do all the
> expand_stack_vars calls.  You'd need to compute it before.
> 
> Though, that change would be still in the wrong place.
> The thing is, it would be a waste of the precious stack space when it isn't
> needed at all (e.g.  when asan will not at compile time do the use after 
> return
> checking, or if it won't do it at runtime, or even if it will do at runtime 
> it will
> waste the space on the stack).
> 
> The following patch fixes it solely for the __asan_stack_malloc_N allocations,
> doesn't enlarge unnecessarily further the actual stack frame.
> Because asan is only supported on FRAME_GROWS_DOWNWARD
> architectures (mips, rs6000 and xtensa are conditional
> FRAME_GROWS_DOWNWARD arches, which for -fsanitize=address or -fstack-
> protector* use FRAME_GROWS_DOWNWARD 1, otherwise 0, others
> supporting asan always just use 1), the assumption for the dynamic stack
> realignment is that the top of the stack frame (aka offset
> 0) is aligned to alignb passed to the function (which is the maximum of alignb
> of all the vars in the frame).  As checked by the assertion in the patch,
> offsets[0] is 0 most of the time and so that assumption is correct, the only
> case when it is not 0 is if -fstack-protector* is on together with -
> fsanitize=address and cfgexpand.cc (create_stack_guard) created a stack
> guard.  That is the only variable which is allocated in the stack frame right
> away, for all others with -fsanitize=address defer_stack_allocation (or 
> -fstack-
> protector*) returns true and so they aren't allocated immediately but handled
> during the frame layout phases.  So, the original frame_offset of 0 is changed
> because of the stack guard to -pointer_size_in_bytes and later at the
>   if (data->asan_vec.is_empty ())
> {
>   align_frame_offset (ASAN_RED_ZONE_SIZE);
>   prev_offset = frame_offset.to_constant ();
> }
> to 

Re: [PATCH] asan, v3: Fix up handling of > 32 byte aligned variables with -fsanitize=address -fstack-protector* [PR110027]

2024-04-11 Thread Richard Biener
On Thu, 11 Apr 2024, Jakub Jelinek wrote:

> On Tue, Mar 26, 2024 at 02:08:02PM +0800, liuhongt wrote:
> > > > So, try to add some other variable with larger size and smaller 
> > > > alignment
> > > > to the frame (and make sure it isn't optimized away).
> > > >
> > > > alignb above is the alignment of the first partition's var, if
> > > > align_frame_offset really needs to depend on the var alignment, it 
> > > > probably
> > > > should be the maximum alignment of all the vars with alignment
> > > > alignb * BITS_PER_UNIT <=3D MAX_SUPPORTED_STACK_ALIGNMENT
> > > >
> > 
> > In asan_emit_stack_protection, when it allocated fake stack, it assume
> > bottom of stack is also aligned to alignb. And the place violated this
> > is the first var partition. which is 32 bytes offsets,  it should be
> > BIGGEST_ALIGNMENT / BITS_PER_UNIT.
> > So I think we need to use MAX (BIGGEST_ALIGNMENT /
> > BITS_PER_UNIT, ASAN_RED_ZONE_SIZE) for the first var partition.
> 
> Your first patch aligned offsets[0] to maximum of alignb and
> ASAN_RED_ZONE_SIZE.  But as I wrote in the reply to that mail, alignb there
> is the alignment of just a single variable which is the first one to appear
> in the sorted list and is placed in the highest spot in the stack frame. 
> That is not necessarily the largest alignment, the sorting ensures that it
> is a variable with the largest size in the frame (and only if several of
> them have equal size, largest alignment from the same sized ones).  Your
> second patch used maximum of BIGGEST_ALIGNMENT / BITS_PER_UNIT and
> ASAN_RED_ZONE_SIZE.  That doesn't change anything at all when using
> -mno-avx512f - offsets[0] is still just 32-byte aligned in that case
> relative to top of frame, just changes the -mavx512f case to be 64-byte
> aligned offsets[0] (aka offsets[0] is then either 0 or -64 instead of either
> 0 or -32).  That will not help if any variable in the frame needs 128-byte,
> 256-byte, 512-byte ...  4096-byte alignment.  If you want to fix the bug in
> the spot you've touched, you'd need to walk all the
> stack_vars[stack_vars_sorted[si2]] for si2 [si + 1, n - 1] and for those
> where the loop would do anything (i.e.
> stack_vars[i2].representative == i2
> && TREE_CODE (decl2) == SSA_NAME
>? SA.partition_to_pseudo[var_to_partition (SA.map, decl2)] == NULL_RTX
>: DECL_RTL (decl2) == pc_rtx
> and the pred applies (but that means also walking the earlier ones!
> because with -fstack-protector* the vars can be processed in several calls) 
> and
> alignb2 * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT
> and compute maximum of those alignments.
> That maximum is already computed,
> data->asan_alignb = MAX (data->asan_alignb, alignb);
> computes that, but you get the final result only after you do all the
> expand_stack_vars calls.  You'd need to compute it before.
> 
> Though, that change would be still in the wrong place.
> The thing is, it would be a waste of the precious stack space when it isn't
> needed at all (e.g.  when asan will not at compile time do the use after
> return checking, or if it won't do it at runtime, or even if it will do at
> runtime it will waste the space on the stack).
> 
> The following patch fixes it solely for the __asan_stack_malloc_N
> allocations, doesn't enlarge unnecessarily further the actual stack frame.
> Because asan is only supported on FRAME_GROWS_DOWNWARD architectures
> (mips, rs6000 and xtensa are conditional FRAME_GROWS_DOWNWARD arches, which
> for -fsanitize=address or -fstack-protector* use FRAME_GROWS_DOWNWARD 1,
> otherwise 0, others supporting asan always just use 1), the assumption for
> the dynamic stack realignment is that the top of the stack frame (aka offset
> 0) is aligned to alignb passed to the function (which is the maximum of alignb
> of all the vars in the frame).  As checked by the assertion in the patch,
> offsets[0] is 0 most of the time and so that assumption is correct, the only
> case when it is not 0 is if -fstack-protector* is on together with
> -fsanitize=address and cfgexpand.cc (create_stack_guard) created a stack
> guard.  That is the only variable which is allocated in the stack frame
> right away, for all others with -fsanitize=address defer_stack_allocation
> (or -fstack-protector*) returns true and so they aren't allocated
> immediately but handled during the frame layout phases.  So, the original
> frame_offset of 0 is changed because of the stack guard to
> -pointer_size_in_bytes and later at the
>   if (data->asan_vec.is_empty ())
> {
>   align_frame_offset (ASAN_RED_ZONE_SIZE);
>   prev_offset = frame_offset.to_constant ();
> }
> to -ASAN_RED_ZONE_SIZE.  The asan_emit_stack_protection code wasn't
> taking this into account though, so essentially assumed in the
> __asan_stack_malloc_N allocated memory it needs to align it such that
> pointer corresponding to offsets[0] is alignb aligned.  But that isn't
> correct if alignb >