diff mbox

Fix minimal alignment calculation for user-aligned types (PR63802)

Message ID 5465A536.8090905@samsung.com
State New
Headers show

Commit Message

Yury Gribov Nov. 14, 2014, 6:46 a.m. UTC
Hi all,

This patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63802 by 
only limiting minimal type alignment with BIGGEST_ALIGNMENT for types 
with no __attribute__((aligned)).

Bootstrapped and regtested on x64.  Ok for trunk?

-Y

Comments

Jakub Jelinek Nov. 14, 2014, 7:02 a.m. UTC | #1
On Fri, Nov 14, 2014 at 09:46:14AM +0300, Yury Gribov wrote:
> Hi all,
> 
> This patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63802 by only
> limiting minimal type alignment with BIGGEST_ALIGNMENT for types with no
> __attribute__((aligned)).
> 
> Bootstrapped and regtested on x64.  Ok for trunk?

The function is primarily used by the C FE for _Alignas, and I have no idea
if such a change is desirable for that very much user visible case.  Joseph?

Alternatively, you can just change ubsan.c caller of min_align_of_type,
use TYPE_USER_ALIGN (type) ? TYPE_ALIGN_UNIT (type) : min_align_of_type (type)
there instead.

> >From 7e5d09453dcff22f591162e1b5c5a115b17b0014 Mon Sep 17 00:00:00 2001
> From: Yury Gribov <y.gribov@samsung.com>
> Date: Thu, 13 Nov 2014 21:29:51 +0300
> Subject: [PATCH] 2014-11-14  Yury Gribov  <y.gribov@samsung.com>
> 
> 	PR sanitizer/63802
> 
> gcc/
> 	* stor-layout.c (min_align_of_type): Respect user alignment
> 	more.
> 
> gcc/testsuite/
> 	* c-c++-common/ubsan/pr63802.c: New test.
> ---
>  gcc/stor-layout.c                          |    2 +-
>  gcc/testsuite/c-c++-common/ubsan/pr63802.c |   23 +++++++++++++++++++++++
>  2 files changed, 24 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/c-c++-common/ubsan/pr63802.c
> 
> diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
> index 431b207..db09855 100644
> --- a/gcc/stor-layout.c
> +++ b/gcc/stor-layout.c
> @@ -2430,9 +2430,9 @@ unsigned int
>  min_align_of_type (tree type)
>  {
>    unsigned int align = TYPE_ALIGN (type);
> -  align = MIN (align, BIGGEST_ALIGNMENT);
>    if (!TYPE_USER_ALIGN (type))
>      {
> +      align = MIN (align, BIGGEST_ALIGNMENT);
>  #ifdef BIGGEST_FIELD_ALIGNMENT
>        align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
>  #endif
> diff --git a/gcc/testsuite/c-c++-common/ubsan/pr63802.c b/gcc/testsuite/c-c++-common/ubsan/pr63802.c
> new file mode 100644
> index 0000000..454c098
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/ubsan/pr63802.c
> @@ -0,0 +1,23 @@
> +/* Limit this to known non-strict alignment targets.  */
> +/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
> +/* { dg-options "-fsanitize=alignment" } */
> +
> +#define __round_mask(x, y) ((__typeof__(x))((y)-1))
> +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
> +
> +struct test_struct {
> +  unsigned long a;
> +  int b;
> +} __attribute__((__aligned__(64)));
> +
> +char a[200];
> +
> +int main ()
> +{
> +  volatile int x = ((struct test_struct*)(round_up((unsigned long)a, 64) + 16))->b;
> +  volatile int y = ((struct test_struct*)(round_up((unsigned long)a, 64) + 15))->b;
> +
> +  return 0;
> +}
> +
> +/* { dg-output "\.c:18:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct test_struct', which requires 64 byte alignment.*" } */
> -- 
> 1.7.9.5
> 


	Jakub
Yury Gribov Nov. 14, 2014, 7:06 a.m. UTC | #2
On 11/14/2014 10:02 AM, Jakub Jelinek wrote:
> On Fri, Nov 14, 2014 at 09:46:14AM +0300, Yury Gribov wrote:
>> Hi all,
>>
>> This patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63802 by only
>> limiting minimal type alignment with BIGGEST_ALIGNMENT for types with no
>> __attribute__((aligned)).
>>
>> Bootstrapped and regtested on x64.  Ok for trunk?
>
> The function is primarily used by the C FE for _Alignas, and I have no idea
> if such a change is desirable for that very much user visible case.  Joseph?
>
> Alternatively, you can just change ubsan.c caller of min_align_of_type,
> use TYPE_USER_ALIGN (type) ? TYPE_ALIGN_UNIT (type) : min_align_of_type (type)
> there instead.

That's what I planned to do initially but change seemed so natural that 
I gave it a try.  Let's wait for Joseph's comment.

-Y
Joseph Myers Nov. 14, 2014, 6:15 p.m. UTC | #3
On Fri, 14 Nov 2014, Jakub Jelinek wrote:

> On Fri, Nov 14, 2014 at 09:46:14AM +0300, Yury Gribov wrote:
> > Hi all,
> > 
> > This patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63802 by only
> > limiting minimal type alignment with BIGGEST_ALIGNMENT for types with no
> > __attribute__((aligned)).
> > 
> > Bootstrapped and regtested on x64.  Ok for trunk?
> 
> The function is primarily used by the C FE for _Alignas, and I have no idea
> if such a change is desirable for that very much user visible case.  Joseph?

If it is true that a type satisfying TYPE_USER_ALIGN will never be 
allocated at an address less-aligned than its TYPE_ALIGN, even if that's 
greater than BIGGEST_ALIGNMENT, then the change seems correct for C11 
_Alignof.
Jakub Jelinek Nov. 17, 2014, 7:20 a.m. UTC | #4
On Fri, Nov 14, 2014 at 06:15:16PM +0000, Joseph Myers wrote:
> On Fri, 14 Nov 2014, Jakub Jelinek wrote:
> 
> > On Fri, Nov 14, 2014 at 09:46:14AM +0300, Yury Gribov wrote:
> > > Hi all,
> > > 
> > > This patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63802 by only
> > > limiting minimal type alignment with BIGGEST_ALIGNMENT for types with no
> > > __attribute__((aligned)).
> > > 
> > > Bootstrapped and regtested on x64.  Ok for trunk?
> > 
> > The function is primarily used by the C FE for _Alignas, and I have no idea
> > if such a change is desirable for that very much user visible case.  Joseph?
> 
> If it is true that a type satisfying TYPE_USER_ALIGN will never be 
> allocated at an address less-aligned than its TYPE_ALIGN, even if that's 
> greater than BIGGEST_ALIGNMENT, then the change seems correct for C11 
> _Alignof.

I think it depends on which target and where.
In structs (unless packed) the user aligned fields should be properly
aligned with respect to start of struct and the struct should have user
alignment in that case, automatic vars these days use alloca with
realignment if not handled better by the target, so should be fine too.
For data section vars and for common vars I think it really depends on the
target.  Perhaps for TYPE_USER_ALIGN use minimum of the TYPE_ALIGN and
MAX_OFILE_ALIGNMENT ?
For heap objects, it really depends on how it has been allocated, but if
allocated through malloc, the extra alignment is never guaranteed.
So, it really depends in malloc counts or not.

	Jakub
Joseph Myers Nov. 17, 2014, 5:46 p.m. UTC | #5
On Mon, 17 Nov 2014, Jakub Jelinek wrote:

> > If it is true that a type satisfying TYPE_USER_ALIGN will never be 
> > allocated at an address less-aligned than its TYPE_ALIGN, even if that's 
> > greater than BIGGEST_ALIGNMENT, then the change seems correct for C11 
> > _Alignof.
> 
> I think it depends on which target and where.
> In structs (unless packed) the user aligned fields should be properly
> aligned with respect to start of struct and the struct should have user
> alignment in that case, automatic vars these days use alloca with
> realignment if not handled better by the target, so should be fine too.
> For data section vars and for common vars I think it really depends on the
> target.  Perhaps for TYPE_USER_ALIGN use minimum of the TYPE_ALIGN and
> MAX_OFILE_ALIGNMENT ?
> For heap objects, it really depends on how it has been allocated, but if
> allocated through malloc, the extra alignment is never guaranteed.
> So, it really depends in malloc counts or not.

The question, for both _Alignas and ubsan, is the alignment guaranteed *in 
valid programs*.

malloc only provides sufficient alignment for types with fundamental 
alignment requirements (although there are various problems with the C11 
wording; see DR#445).  So if you use malloc to allocate a type with an 
extended alignment requirement (without doing extra realignment on the 
result of malloc), that's not a valid program.  And if an alignment is 
larger than MAX_OFILE_ALIGNMENT, you get an error for declaring non-stack 
variables requiring that alignment.  So I don't think there's any need to 
check MAX_OFILE_ALIGNMENT here.
Jakub Jelinek Nov. 17, 2014, 5:54 p.m. UTC | #6
On Mon, Nov 17, 2014 at 05:46:55PM +0000, Joseph Myers wrote:
> On Mon, 17 Nov 2014, Jakub Jelinek wrote:
> 
> > > If it is true that a type satisfying TYPE_USER_ALIGN will never be 
> > > allocated at an address less-aligned than its TYPE_ALIGN, even if that's 
> > > greater than BIGGEST_ALIGNMENT, then the change seems correct for C11 
> > > _Alignof.
> > 
> > I think it depends on which target and where.
> > In structs (unless packed) the user aligned fields should be properly
> > aligned with respect to start of struct and the struct should have user
> > alignment in that case, automatic vars these days use alloca with
> > realignment if not handled better by the target, so should be fine too.
> > For data section vars and for common vars I think it really depends on the
> > target.  Perhaps for TYPE_USER_ALIGN use minimum of the TYPE_ALIGN and
> > MAX_OFILE_ALIGNMENT ?
> > For heap objects, it really depends on how it has been allocated, but if
> > allocated through malloc, the extra alignment is never guaranteed.
> > So, it really depends in malloc counts or not.
> 
> The question, for both _Alignas and ubsan, is the alignment guaranteed *in 
> valid programs*.
> 
> malloc only provides sufficient alignment for types with fundamental 
> alignment requirements (although there are various problems with the C11 
> wording; see DR#445).  So if you use malloc to allocate a type with an 
> extended alignment requirement (without doing extra realignment on the 
> result of malloc), that's not a valid program.  And if an alignment is 
> larger than MAX_OFILE_ALIGNMENT, you get an error for declaring non-stack 
> variables requiring that alignment.  So I don't think there's any need to 
> check MAX_OFILE_ALIGNMENT here.

If so, then Yuri's original patch (the one changing min_align_of_type)
should be fine, right?

	Jakub
Joseph Myers Nov. 17, 2014, 6:29 p.m. UTC | #7
On Mon, 17 Nov 2014, Jakub Jelinek wrote:

> > The question, for both _Alignas and ubsan, is the alignment guaranteed *in 
> > valid programs*.
> > 
> > malloc only provides sufficient alignment for types with fundamental 
> > alignment requirements (although there are various problems with the C11 
> > wording; see DR#445).  So if you use malloc to allocate a type with an 
> > extended alignment requirement (without doing extra realignment on the 
> > result of malloc), that's not a valid program.  And if an alignment is 
> > larger than MAX_OFILE_ALIGNMENT, you get an error for declaring non-stack 
> > variables requiring that alignment.  So I don't think there's any need to 
> > check MAX_OFILE_ALIGNMENT here.
> 
> If so, then Yuri's original patch (the one changing min_align_of_type)
> should be fine, right?

Yes.
diff mbox

Patch

From 7e5d09453dcff22f591162e1b5c5a115b17b0014 Mon Sep 17 00:00:00 2001
From: Yury Gribov <y.gribov@samsung.com>
Date: Thu, 13 Nov 2014 21:29:51 +0300
Subject: [PATCH] 2014-11-14  Yury Gribov  <y.gribov@samsung.com>

	PR sanitizer/63802

gcc/
	* stor-layout.c (min_align_of_type): Respect user alignment
	more.

gcc/testsuite/
	* c-c++-common/ubsan/pr63802.c: New test.
---
 gcc/stor-layout.c                          |    2 +-
 gcc/testsuite/c-c++-common/ubsan/pr63802.c |   23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/c-c++-common/ubsan/pr63802.c

diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 431b207..db09855 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -2430,9 +2430,9 @@  unsigned int
 min_align_of_type (tree type)
 {
   unsigned int align = TYPE_ALIGN (type);
-  align = MIN (align, BIGGEST_ALIGNMENT);
   if (!TYPE_USER_ALIGN (type))
     {
+      align = MIN (align, BIGGEST_ALIGNMENT);
 #ifdef BIGGEST_FIELD_ALIGNMENT
       align = MIN (align, BIGGEST_FIELD_ALIGNMENT);
 #endif
diff --git a/gcc/testsuite/c-c++-common/ubsan/pr63802.c b/gcc/testsuite/c-c++-common/ubsan/pr63802.c
new file mode 100644
index 0000000..454c098
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/pr63802.c
@@ -0,0 +1,23 @@ 
+/* Limit this to known non-strict alignment targets.  */
+/* { dg-do run { target { i?86-*-linux* x86_64-*-linux* } } } */
+/* { dg-options "-fsanitize=alignment" } */
+
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+
+struct test_struct {
+  unsigned long a;
+  int b;
+} __attribute__((__aligned__(64)));
+
+char a[200];
+
+int main ()
+{
+  volatile int x = ((struct test_struct*)(round_up((unsigned long)a, 64) + 16))->b;
+  volatile int y = ((struct test_struct*)(round_up((unsigned long)a, 64) + 15))->b;
+
+  return 0;
+}
+
+/* { dg-output "\.c:18:\[0-9]*: \[^\n\r]*member access within misaligned address 0x\[0-9a-fA-F]* for type 'struct test_struct', which requires 64 byte alignment.*" } */
-- 
1.7.9.5